programacion - Java 8: ¿Cómo trabajo con métodos de lanzamiento de excepción en las transmisiones?
setbounds java (7)
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)
.
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<A> as = ...
as.forEach(a -> a.foo());
}
Pregunta: ¿Cómo manejo adecuadamente la excepción? El código no se compila 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?
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)));
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 Controversy , 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 recopilar excepciones que no funcionan como una sola. De lo contrario, podría recopilarlos 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.
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<A> 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()
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<A> 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);
}
}
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 trickery ):
for (A a : (Iterable<A>) 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)
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<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
throw Throwables.propagate(e);
}
});
}