При использовании внешней итерации над циклом Iterable
мы используем break
или return
из расширенного цикла for-each как:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
Как мы можем break
или с return
помощью внутренней итерации в лямбда - выражения Java 8 , как:
someObjects.forEach(obj -> {
//what to do here?
})
for
утверждение.forEach()
. Решение не хорошо, но это возможно. Смотрите мой ответ ниже.if
условие внутриforEach
сделает свое дело.Ответы:
Если вам это нужно, вы не должны использовать
forEach
, но один из других методов, доступных в потоках; какой, зависит от вашей цели.Например, если целью этого цикла является поиск первого элемента, который соответствует некоторому предикату:
(Примечание: это не будет повторять всю коллекцию, потому что потоки лениво оцениваются - это остановится на первом объекте, который соответствует условию).
Если вы просто хотите узнать, есть ли в коллекции элемент, для которого выполняется условие, вы можете использовать
anyMatch
:источник
return
оператор изfindSomething
метода.break
чаще всего ассоциируется с операцией типа take while.forEach
для этого; Вместо этого вы должны использовать другой, более подходящий метод.forEach
» была технически неверной. Я также предпочитаю ваше решение, однако я могу представить себе варианты использования, когда решение, представленное в моем ответе, предпочтительнее: когда цикл должен быть завершен из-за реального исключения. Я согласен, что вы не должны обычно использовать исключения для управления потоком.Это является возможным
Iterable.forEach()
(но не надежно сStream.forEach()
). Решение не хорошо, но это возможно.ВНИМАНИЕ : Вы не должны использовать его для управления бизнес-логикой, а исключительно для обработки исключительной ситуации, возникающей во время выполнения
forEach()
. Например, если ресурс внезапно перестает быть доступным, один из обработанных объектов нарушает контракт (например, контракт говорит, что все элементы в потоке не должны быть,null
но внезапно и неожиданно одним из них являетсяnull
) и т. Д.Согласно документации для
Iterable.forEach()
:Таким образом, вы бросаете исключение, которое немедленно прервет внутренний цикл.
Код будет примерно таким - я не могу сказать, что мне это нравится, но он работает. Вы создаете свой собственный класс,
BreakException
который расширяетсяRuntimeException
.Обратите внимание , что
try...catch
это не вокруг лямбда - выражения, а вокруг весьforEach()
метод. Чтобы сделать его более видимым, посмотрите следующую транскрипцию кода, которая показывает это более четко:источник
Stream.forEach
это не дает такой же строгой гарантии о том, что исключения передаются вызывающей стороне, поэтому создание исключения не обязательно будет работать таким образомStream.forEach
.Iterable.forEach()
, но я добавил вашу точку зрения в мой текст только для полноты.Возврат в лямбде равен продолжению в for-each, но нет эквивалента перерыву. Вы можете просто сделать возврат, чтобы продолжить:
источник
Ниже вы найдете решение, которое я использовал в проекте. Вместо этого
forEach
просто используйтеallMatch
:источник
Либо вам нужно использовать метод, который использует предикат, указывающий, следует ли продолжать (то есть вместо этого есть перерыв), либо вам нужно сгенерировать исключение - что, конечно, очень уродливый подход.
Таким образом, вы можете написать такой
forEachConditional
метод:Вместо
Predicate<T>
этого вы можете захотеть определить свой собственный функциональный интерфейс с помощью того же общего метода (что-то, принимающего aT
и возвращающего abool
), но с именами, которые более четко обозначают ожидание -Predicate<T>
здесь не идеально.источник
takeWhile
операция, и этот вопрос является лишь одним из тех, которые демонстрируют, насколько ощущается его недостаток в Streams API.Вы можете использовать java8 + rxjava .
источник
Для максимальной производительности в параллельных операциях используйте findAny (), который похож на findFirst ().
Однако, если требуется стабильный результат, используйте вместо него findFirst ().
Также обратите внимание, что соответствующие шаблоны (anyMatch () / allMatch) будут возвращать только логическое значение, вы не получите соответствующий объект.
источник
Обновление с помощью Java 9+
takeWhile
:источник
Я достиг чего-то вроде этого
источник
Вы можете добиться этого, используя сочетание peek (..) и anyMatch (..).
Используя ваш пример:
Или просто напишите универсальный метод util:
И затем используйте это, как это:
источник
Что насчет этого:
Где
BooleanWrapper
класс, который вы должны реализовать для управления потоком.источник
!condition.ok()
, но, тем не менее, не предотвращаетforEach()
зацикливание всех объектов. Если медленная часть являетсяforEach()
итерацией, а не ее потребителем (например, она получает объекты из медленного сетевого соединения), то этот подход не очень полезен.Он будет выполнять только ту операцию, в которой он находит совпадение, а после поиска совпадения останавливает свою итерацию.
источник
Я бы предложил использовать anyMatch. Пример:-
Вы можете сослаться на этот пост для понимания любого соответствия: - https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/
источник