Cuando usamos iteración externa sobre una Iterable, usamos breako returndesde un ciclo for-each mejorado como:
for (SomeObject obj : someObjects) {
   if (some_condition_met) {
      break; // or return obj
   }
}¿Cómo podemos breako returnusar la iteración interna en una expresión lambda de Java 8 como:
someObjects.forEach(obj -> {
   //what to do here?
})
fordeclaración real .forEach(). La solución no es agradable, pero es posible. Vea mi respuesta a continuación.ifcondición simple dentro delforEachhará 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
returndeclaración de unfindSomethingmétodo.breakse asocia más habitualmente con una toma mientras que - tipo de operación.forEachpara 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,nullpero 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
BreakExceptionque se extiendeRuntimeException.Observe que no
try...catchestá 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.forEachno 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,
forEachsolo 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
forEachConditionalmé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 unTy devuelve unbool) pero con nombres que indican la expectativa más claramente,Predicate<T>no es ideal aquí.fuente
takeWhileoperació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
BooleanWrapperhay 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