Я получил эту ошибку, потому что мой контроль версий был установлен, чтобы игнорировать мою папку с bin. Очень глупо, но, возможно, кому-то это поможет.
Я не хочу проверять размер файла, потому что файл МОЖЕТ быть размером 0 байт (бесполезный файл, в большинстве случаев, правда, но все же). А проверка только на наличие пустых имен файлов позволяет мне решить, можно ли отказаться от конкретного Part
.
Если я могу избежать этого, я не хочу итерировать части более одного раза.
Так что я думаю, что я мог бы сделать, это создать логический флаг, для которого я установил значение true, если я в конечном итоге загрузлю что-нибудь ...
boolean uploadedAnything = false;
Так как я использую parallelStream
, обновление этого флага потребует некоторой синхронизации. Я уже синхронизируюсь в потоке out
, так почему бы просто не выбросить его туда?
synchronized (out) {
out.print(String.format("uploading '%s': %s, %d%s...", fileName, p.getContentType(), sizeInKb, "KB"));
if (success){
out.println("OK<br>");
uploadedAnything = true;
}
else out.println("FAILED<br>");
}
, за исключением того, что Java отказывается компилировать это, потому что
локальные переменные, на которые ссылаются из лямбда-выражение должно быть окончательным или эффективно окончательным
blockquote>, которое не имеет ничего общего с блоком
synchronized
, но больше относится к тому факту, что все это заключено в[ 1127] Полагаю, заменаboolean uploadedAnything = false; req.getParts().parallelStream().forEach(p -> { //`uploadedAnything` gets changed here });
boolean
наAtomicBoolean
может сработать, но мне не очень нравится это решение, потому что я ненавижу добавлять синхронизацию, которая, как я ЗНАЮ, бесполезна.
Итак ... следующая идея:
Вместо перехода к
forEach
, давайте перейдем кmap
. Таким образом, мы превращаем наш списокPart
в список операторов независимо от того, действительно ли загрузка файла, соответствующего этомуPart
, действительно удалась.Т.е.
boolean uploadedAnything = req.getParts().parallelStream().map(p -> { [...] return success; }).matchAny(Predicate.isEqual(true));
за исключением того, что мы не можем этого сделать, потому что
matchAny
затем замыкает накоротко из-за обработки всех файлов. Упс.Итак ...
List<Boolean> uploadStatus = req.getParts().parallelStream().map(p -> { [...] return success; }).collect(Collectors.toList()); boolean uploadedAnything = uploadStatus.stream().anyMatch(Predicate.isEqual(true));
... хорошо, это работает, но теперь я создал целый кровавый список логических значений, только чтобы получить один логический.
Думаю, мы могли бы сделать фолд ...
boolean uploadedAnything = req.getParts().parallelStream().fold(false,(status,p) -> { [...] return status || success; });
... за исключением того, что Java не поддерживает сгибы, и одна вещь, которая приближается к несколько схожей функциональности, требует третьего аргумента, "Combiner". Поэтому мы должны поискать в Интернете, чтобы выяснить, почему и как этот Combiner действительно вступает в игру.
Найдя https://stackoverflow.com/a/24316429/3322533 , фрагмент становится
boolean uploadedAnything = req.getParts().parallelStream().reduce(false,(status,p) -> { [...] return status || success; },(accA, accB) -> accA || accB);
, который мы можем переписать в
[1138 ] Этот STILL не складывается, потому что он наносит ущерб порядку операций (что, к счастью, в данном случае не имеет значения), но он выполняет свою работу.boolean uploadedAnything = req.getParts().parallelStream().reduce(false,(status,p) -> { [...] return status || success; },Boolean::logicalOr);