Ответ 1
Не должно выглядеть так:
boolean areAllSuccessful = entries.stream()
.map(entry -> entry.isSuccessful())
.reduce(Boolean.TRUE, Boolean::logicalAnd);
В настоящее время я занимаюсь проблемой преобразования циклов, которые используют побитовые операции с использованием Lambdas в Java 8.
Учитывая набор сложных записей, требуется, чтобы цикл пересекал ВСЕ записи и вызывал на них заданный метод (метод возвращает логическое значение). Затем верните результат.
Другими словами, мне нужно вызвать метод для всех записей и сохранить результат. Причина в том, что каждая запись независимо выполняет сложную операцию и должна выполняться. Конечный результат представляет собой комбинацию результатов.
Фрагмент кода:
boolean areAllSuccessful = true;
for (SomeEntry entry : entries) {
areAllSuccessful = areAllSuccessful & entry.doComplexAction(); // keep calling the method on other entries regardless of the result.
}
return areAllSuccessful;
Проблема в том, что функции лямбда в Java 8 обычно выполняют операции короткого замыкания (как только ложная запись обнаружена, "цикл" ломается, и возвращается ложный результат).
Мое лучшее решение до сих пор заключалось в использовании комбинации карт/фильтров/счетчиков:
return entries
.stream()
.map(entry -> entry.doComplexAction())
.filter(result -> result == false)
.count() > 0
Есть ли более умный/чистый способ сделать это?
Спасибо!
Не должно выглядеть так:
boolean areAllSuccessful = entries.stream()
.map(entry -> entry.isSuccessful())
.reduce(Boolean.TRUE, Boolean::logicalAnd);
Самый простой и эффективный способ - использовать ссылку метода с allMatch()
return entries.stream().allMatch(SomeEntry::isSuccessful);
Если у вас есть 1000 элементов, используйте вместо этого parallelStream()
.
Это не обрабатывает каждый элемент (он возвращается с первой false
), поэтому, если ваш метод isSuccessful()
имеет побочные эффекты, это плохое имя, и вы должны переименовать его или реорганизовать код для выполнения побочных эффектов в process()
(или аналогичном) методе и isSuccessful()
возвращает результат, бросая IllegalStateException
, если process()
не был вызван.
Если вы не реорганизуете, какой-то разработчик (включая вас) вызовет isSuccessful()
, не понимая, что он "делает материал", что может быть плохо.
Вам не нужно map()
, если вы собираетесь использовать count()
:
return !(entries
.stream()
.filter(entry -> !entry.isSuccessful())
.count() > 0);
Если метод isSuccessful()
не имел побочных эффектов, и все, что вам нужно знать, было, если все записи были успешными, вы могли бы использовать allMatch()
:
return entries
.stream()
.allMatch(entry -> entry.isSuccessful());
Это действительно операция короткого замыкания, которая вернет false
, как только найдет запись, где isSuccessful()
- false
, не потребляя весь поток, если это необходимо. Но вы уже прокомментировали, что isSuccesful()
действительно означает "выполнить некоторые сложные действия, а затем сказать мне, если они были успешными", поэтому он не применяется.