Aprecio muito os novos recursos do Java 8 sobre interfaces lambdas e métodos padrão. No entanto, ainda me aborreço com exceções verificadas. Por exemplo, se eu apenas quiser listar todos os campos visíveis de um objeto, gostaria de simplesmente escrever isto:
Arrays.asList(p.getClass().getFields()).forEach(
f -> System.out.println(f.get(p))
);
No entanto, como o get
método pode lançar uma exceção verificada, o que não concorda com o Consumer
contrato de interface, devo capturar essa exceção e escrever o seguinte código:
Arrays.asList(p.getClass().getFields()).forEach(
f -> {
try {
System.out.println(f.get(p));
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
);
No entanto, na maioria dos casos, eu só quero que a exceção seja lançada como um RuntimeException
e deixe o programa manipular, ou não, a exceção sem erros de compilação.
Portanto, gostaria de ter sua opinião sobre minha solução controversa para aborrecimento de exceções verificadas. Para isso, criei uma interface auxiliar ConsumerCheckException<T>
e uma função de utilitário rethrow
( atualizada de acordo com a sugestão do comentário de Doval ) da seguinte forma:
@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;
}
}
E agora eu posso escrever:
Arrays.asList(p.getClass().getFields()).forEach(
rethrow(f -> System.out.println(f.get(p)))
);
Não tenho certeza de que esse seja o melhor idioma para contornar as exceções verificadas, mas, como expliquei, gostaria de ter uma maneira mais conveniente de obter meu primeiro exemplo sem lidar com as exceções verificadas, e essa é a maneira mais simples que encontrei para fazer isso.
sneakyThrow
dentro de rethrow
para lançar a exceção verificada original em vez de agrupá-la em um RuntimeException
. Como alternativa, você pode usar a @SneakyThrows
anotação do Projeto Lombok que faz a mesma coisa.
Consumer
s in forEach
podem ser executados de maneira paralela ao usar Stream
s paralelos . Um lançamento jogável de dentro do consumidor será propagado para o encadeamento de chamada, que 1) não interromperá os outros consumidores em execução simultânea, o que pode ou não ser apropriado, e 2) se mais de um consumidor lançar algo, apenas um dos lançamentos será visto pelo thread de chamada.