Apprezzo molto le nuove funzionalità di Java 8 su lambdas e le interfacce dei metodi predefiniti. Tuttavia, mi annoio ancora con le eccezioni verificate. Ad esempio, se voglio solo elencare tutti i campi visibili di un oggetto, vorrei semplicemente scrivere questo:
Arrays.asList(p.getClass().getFields()).forEach(
f -> System.out.println(f.get(p))
);
Tuttavia, poiché il get
metodo potrebbe generare un'eccezione controllata, che non è d'accordo con il Consumer
contratto di interfaccia, allora devo prendere quell'eccezione e scrivere il seguente codice:
Arrays.asList(p.getClass().getFields()).forEach(
f -> {
try {
System.out.println(f.get(p));
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
);
Tuttavia, nella maggior parte dei casi, voglio solo generare l'eccezione come a RuntimeException
e lasciare che il programma gestisca o meno l'eccezione senza errori di compilazione.
Quindi, vorrei avere la tua opinione sulla mia controversa soluzione alternativa per il fastidio delle eccezioni verificate. A tal fine, ho creato un'interfaccia ausiliaria ConsumerCheckException<T>
e una funzione di utilità rethrow
( aggiornata secondo il suggerimento del commento di Doval ) come segue:
@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 ora posso solo scrivere:
Arrays.asList(p.getClass().getFields()).forEach(
rethrow(f -> System.out.println(f.get(p)))
);
Non sono sicuro che questo sia il modo di dire migliore per aggirare le eccezioni verificate, ma come ho spiegato, vorrei avere un modo più conveniente di ottenere il mio primo esempio senza occuparmi delle eccezioni verificate e questo è il modo più semplice che ho trovato per farlo.
sneakyThrow
inside of rethrow
per lanciare l'eccezione originale e controllata invece di racchiuderla in a RuntimeException
. In alternativa puoi usare l' @SneakyThrows
annotazione di Project Lombok che fa la stessa cosa.
Consumer
s in forEach
può essere eseguito in modo parallelo quando si usano Stream
s in parallelo . Un lanciatore generato dal withing del consumatore si propaga quindi al thread chiamante, che 1) non bloccherà gli altri consumatori che gestiscono contemporaneamente, il che può essere o non essere appropriato, e 2) se più di uno dei consumatori lancia qualcosa, solo uno dei lanci sarà visto dal thread chiamante.