Cuando usamos iteración externa sobre una Iterable
, usamos break
o return
desde un ciclo for-each mejorado como:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
¿Cómo podemos break
o return
usar la iteración interna en una expresión lambda de Java 8 como:
someObjects.forEach(obj -> {
//what to do here?
})
for
declaración real .forEach()
. La solución no es agradable, pero es posible. Vea mi respuesta a continuación.if
condición simple dentro delforEach
hará el truco.Respuestas:
Si necesita esto, no debe usar
forEach
, sino uno de los otros métodos disponibles en las transmisiones; cuál depende de cuál sea su objetivo.Por ejemplo, si el objetivo de este ciclo es encontrar el primer elemento que coincida con algún predicado:
(Nota: Esto no repetirá toda la colección, porque las secuencias se evalúan de forma perezosa; se detendrá en el primer objeto que coincida con la condición).
Si solo desea saber si hay un elemento en la colección para el cual la condición es verdadera, puede usar
anyMatch
:fuente
return
declaración de unfindSomething
método.break
se asocia más habitualmente con una toma mientras que - tipo de operación.forEach
para esto; deberías usar otro método más apropiado en su lugar.forEach
" era técnicamente incorrecta. También prefiero su solución, sin embargo, puedo imaginar casos de uso en los que la solución provista en mi respuesta es preferible: cuando el ciclo debe finalizar debido a una excepción real . Estoy de acuerdo en que generalmente no debe usar las excepciones para controlar el flujo.Esto es posible para
Iterable.forEach()
(pero no confiablemente conStream.forEach()
). La solución no es agradable, pero es posible.ADVERTENCIA : No debe usarlo para controlar la lógica de negocios, sino únicamente para manejar una situación excepcional que ocurre durante la ejecución de
forEach()
. Tal como un recurso deja de ser accesible de repente, uno de los objetos procesados está violando un contrato (por ejemplo, el contrato dice que todos los elementos en la secuencia no deben ser,null
pero de repente e inesperadamente uno de ellos esnull
), etc.De acuerdo con la documentación para
Iterable.forEach()
:Entonces lanzas una excepción que inmediatamente romperá el ciclo interno.
El código será algo así: no puedo decir que me guste, pero funciona. Creas tu propia clase
BreakException
que se extiendeRuntimeException
.Observe que no
try...catch
está alrededor de la expresión lambda, sino alrededor del método completo . Para hacerlo más visible, vea la siguiente transcripción del código que lo muestra más claramente:forEach()
fuente
Stream.forEach
no no proporcionan la misma garantía fuerte acerca de las excepciones que se transmite a la persona que llama, por lo que no se garantiza una excepción a trabajar de esta manera paraStream.forEach
.Iterable.forEach()
, pero agregué su punto a mi texto solo por lo completo.Un retorno en una lambda es igual a continuar en un para cada uno, pero no hay equivalente a un descanso. Solo puede hacer un regreso para continuar:
fuente
A continuación encontrará la solución que utilicé en un proyecto. En su lugar,
forEach
solo useallMatch
:fuente
O necesita usar un método que usa un predicado que indica si debe continuar (por lo que tiene el descanso) o necesita lanzar una excepción, que es un enfoque muy feo, por supuesto.
Entonces podrías escribir un
forEachConditional
método como este:En lugar de
Predicate<T>
eso, es posible que desee definir su propia interfaz funcional con el mismo método general (algo que toma unT
y devuelve unbool
) pero con nombres que indican la expectativa más claramente,Predicate<T>
no es ideal aquí.fuente
takeWhile
operación clásica , y esta pregunta es una de las que demuestran cuánto se siente su falta en la API de Streams.Puede usar java8 + rxjava .
fuente
Para obtener el máximo rendimiento en operaciones paralelas, use findAny (), que es similar a findFirst ().
Sin embargo, si se desea un resultado estable, use findFirst () en su lugar.
También tenga en cuenta que los patrones coincidentes (anyMatch () / allMatch) devolverán solo booleanos, no obtendrá objetos coincidentes.
fuente
Actualice con Java 9+ con
takeWhile
:fuente
He logrado algo como esto
fuente
Puede lograrlo usando una mezcla de peek (..) y anyMatch (..).
Usando tu ejemplo:
O simplemente escriba un método de utilidad genérico:
Y luego úsalo, así:
fuente
¿Qué hay de este?
¿Dónde
BooleanWrapper
hay una clase que debe implementar para controlar el flujo?fuente
!condition.ok()
, sin embargo, no evita que se repitaforEach()
sobre todos los objetos de todos modos. Si la parte lenta es laforEach()
iteración y no su consumidor (por ejemplo, obtiene objetos de una conexión de red lenta), entonces este enfoque no es muy útil.Solo realizará operaciones donde encuentre coincidencia, y después de encontrar coincidencia, detendrá su iteración.
fuente
Sugeriría usar anyMatch. Ejemplo:-
Puede consultar esta publicación para comprender anyMatch: - https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/
fuente