Java 8: ¿Cómo trabajo con métodos de lanzamiento de excepción en las transmisiones?

Supongamos que tengo una clase y un método

class A { void foo() throws Exception() { ... } } 

Ahora me gustaría llamar a foo para cada instancia de A entregada por una secuencia como:

 void bar() throws Exception { Stream as = ... as.forEach(a -> a.foo()); } 

Pregunta: ¿Cómo manejo adecuadamente la excepción? El código no se comstack en mi máquina porque no manejo las posibles excepciones que puede lanzar Foo (). The throws Exception of bar parece ser inútil aquí. ¿Porqué es eso?

    Debe ajustar su llamada de método a otra, donde no arroje excepciones comprobadas . Todavía puede lanzar cualquier cosa que sea una subclase de RuntimeException .

    Un modismo de envoltura normal es algo así como:

     private void safeFoo(final A a) { try { a.foo(); } catch (Exception ex) { throw new RuntimeException(ex); } } 

    (Supertype excepción de Exception solo se utiliza como ejemplo, nunca intente atraparlo usted mismo)

    Luego puede llamarlo con: as.forEach(this::safeFoo) .

    Si todo lo que quiere es invocar a foo , y prefiere propagar la excepción como está (sin envolver), también puede usar Java for bucle en su lugar (después de convertir el flujo en un Iterable con algún truco ):

     for (A a : (Iterable) as::iterator) { a.foo(); } 

    Esto es, al menos, lo que hago en mis pruebas JUnit, donde no quiero tomar el trabajo de envolver mis excepciones marcadas (y de hecho prefiero mis pruebas para arrojar las originales sin envolver)

    Esta pregunta puede ser un poco vieja, pero porque creo que la respuesta “correcta” aquí es solo una de las formas que puede llevar a algunos problemas ocultos. Problemas más adelante en su código. Incluso si hay un poco de controversia , existen excepciones controladas por un motivo.

    La manera más elegante que, en mi opinión, puede encontrar, fue dada por Misha aquí Aggregate exceptions runtime en Java 8 solo realizando las acciones en “futuros”. Para que pueda ejecutar todas las partes que trabajan y recostackr excepciones que no funcionan como una sola. De lo contrario, podría recostackrlos todos en una lista y procesarlos más tarde.

    Un enfoque similar proviene de Benji Weber . Sugiere crear un tipo propio para recolectar piezas que funcionen y que no funcionen.

    Dependiendo de lo que realmente desee lograr, una asignación simple entre los valores de entrada y los valores de salida ocurridos Las excepciones también pueden funcionar para usted.

    Si no le gusta ninguna de estas formas, considere usar (según la Excepción original) al menos una excepción propia.

    Sugiero usar la clase Google Throwables de Guava

    propagar ( arrojable arrojable)

    Propaga los lanzamientos como están si es una instancia de RuntimeException o Error, o si no como último recurso, lo envuelve en una RuntimeException y luego se propaga. **

     void bar() { Stream as = ... as.forEach(a -> { try { a.foo() } catch(Exception e) { throw Throwables.propagate(e); } }); } 

    Puede envolver y desenvolver excepciones de esta manera.

     class A { void foo() throws Exception { throw new Exception(); } }; interface Task { void run() throws Exception; } static class TaskException extends RuntimeException { private static final long serialVersionUID = 1L; public TaskException(Exception e) { super(e); } } void bar() throws Exception { Stream as = Stream.generate(()->new A()); try { as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo() } catch (TaskException e) { throw (Exception)e.getCause(); } } static void wrapException(Task task) { try { task.run(); } catch (Exception e) { throw new TaskException(e); } } 

    Es posible que desee hacer uno de los siguientes:

    • propagar la excepción marcada,
    • envolverlo y propagar la excepción sin marcar, o
    • capte la excepción y detenga la propagación.

    Varias bibliotecas te permiten hacerlo fácilmente. El siguiente ejemplo está escrito usando mi biblioteca NoException .

     // Propagate checked exception as.forEach(Exceptions.sneak().consumer(A::foo)); // Wrap and propagate unchecked exception as.forEach(Exceptions.wrap().consumer(A::foo)); as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo)); // Catch the exception and stop propagation (using logging handler for example) as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo))); 

    Forma más legible:

     class A { void foo() throws MyException() { ... } } 

    Solo forEach() en una RuntimeException para forEach() por cada forEach()

      void bar() throws MyException { Stream as = ... try { as.forEach(a -> { try { a.foo(); } catch(MyException e) { throw new RuntimeException(e); } }); } catch(RuntimeException e) { throw (MyException) e.getCause(); } } 

    Aunque en este punto no me detendré en contra de alguien si dicen saltear las secuencias e ir con un bucle for, a menos que:

    • no está creando su flujo utilizando Collection.stream() , es decir, no una traducción directa a un bucle for.
    • estás tratando de usar parallelstream()