Aprecio mucho las nuevas características de Java 8 sobre lambdas e interfaces de métodos predeterminados. Sin embargo, todavía me aburro con las excepciones marcadas. Por ejemplo, si solo quiero enumerar todos los campos visibles de un objeto, me gustaría simplemente escribir esto:
Arrays.asList(p.getClass().getFields()).forEach(
f -> System.out.println(f.get(p))
);
Sin embargo, dado que el get
método podría arrojar una excepción marcada, que no está de acuerdo con el Consumer
contrato de interfaz, entonces debo detectar esa excepción y escribir el siguiente código:
Arrays.asList(p.getClass().getFields()).forEach(
f -> {
try {
System.out.println(f.get(p));
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
);
Sin embargo, en la mayoría de los casos, solo quiero que la excepción se arroje como ay RuntimeException
deje que el programa maneje, o no, la excepción sin errores de compilación.
Por lo tanto, me gustaría tener su opinión sobre mi solución controvertida para las molestias de excepciones comprobadas. Con ese fin, creé una interfaz auxiliar ConsumerCheckException<T>
y una función de utilidad rethrow
( actualizada de acuerdo con la sugerencia del comentario de Doval ) de la siguiente manera:
@FunctionalInterface
public interface ConsumerCheckException<T>{
void accept(T elem) throws Exception;
}
public class Wrappers {
public static <T> Consumer<T> rethrow(ConsumerCheckException<T> c) {
return elem -> {
try {
c.accept(elem);
} catch (Exception ex) {
/**
* within sneakyThrow() we cast to the parameterized type T.
* In this case that type is RuntimeException.
* At runtime, however, the generic types have been erased, so
* that there is no T type anymore to cast to, so the cast
* disappears.
*/
Wrappers.<RuntimeException>sneakyThrow(ex);
}
};
}
/**
* Reinier Zwitserloot who, as far as I know, had the first mention of this
* technique in 2009 on the java posse mailing list.
* http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
*/
public static <T extends Throwable> T sneakyThrow(Throwable t) {
throw (T) t;
}
}
Y ahora solo puedo escribir:
Arrays.asList(p.getClass().getFields()).forEach(
rethrow(f -> System.out.println(f.get(p)))
);
No estoy seguro de que este sea el mejor modismo para cambiar las excepciones marcadas, pero como expliqué, me gustaría tener una forma más conveniente de lograr mi primer ejemplo sin tratar con las excepciones marcadas y esta es la forma más simple que encontré para hacerlo.
sneakyThrow
dentro rethrow
para lanzar la excepción original, marcada, en lugar de envolverla en un RuntimeException
. Alternativamente, podría usar la @SneakyThrows
anotación del Proyecto Lombok que hace lo mismo.
Consumer
s en forEach
puede ejecutarse en forma paralela cuando se usa Stream
s paralela . Un lanzamiento arrojado desde el consumidor se propagará al hilo de llamada, que 1) no detendrá a los otros consumidores que se ejecutan simultáneamente, lo que puede ser apropiado o no, y 2) si más de uno de los consumidores arroja algo, solo uno de los lanzamientos será visto por el hilo de llamada.