Bardzo doceniam nowe funkcje Java 8 dotyczące lambd i interfejsów metod domyślnych. Nadal jednak nudzą mnie sprawdzone wyjątki. Na przykład, jeśli chcę tylko wymienić wszystkie widoczne pola obiektu, chciałbym po prostu napisać:
Arrays.asList(p.getClass().getFields()).forEach(
f -> System.out.println(f.get(p))
);
Ponieważ jednak get
metoda może zgłosić sprawdzony wyjątek, co nie jest zgodne z Consumer
umową interfejsu, muszę złapać ten wyjątek i napisać następujący kod:
Arrays.asList(p.getClass().getFields()).forEach(
f -> {
try {
System.out.println(f.get(p));
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
);
Jednak w większości przypadków chcę, aby wyjątek został zgłoszony jako a RuntimeException
i pozwolił programowi obsłużyć wyjątek bez błędów kompilacji.
Tak więc chciałbym poznać Twoją opinię na temat mojego kontrowersyjnego obejścia problemu sprawdzonych irytacji wyjątków. W tym celu stworzyłem interfejs pomocniczy ConsumerCheckException<T>
i funkcję narzędzia rethrow
( zaktualizowaną zgodnie z sugestią komentarza Dovala ) w następujący sposób:
@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;
}
}
A teraz mogę po prostu napisać:
Arrays.asList(p.getClass().getFields()).forEach(
rethrow(f -> System.out.println(f.get(p)))
);
Nie jestem pewien, czy jest to najlepszy idiom do odwrócenia sprawdzonych wyjątków, ale jak wyjaśniłem, chciałbym mieć wygodniejszy sposób na osiągnięcie mojego pierwszego przykładu bez zajmowania się sprawdzonymi wyjątkami i jest to prostszy sposób, który znalazłem zrobić to.
sneakyThrow
wewnątrz, rethrow
aby rzucić oryginalny, sprawdzony wyjątek, zamiast owijać go w RuntimeException
. Alternatywnie możesz użyć @SneakyThrows
adnotacji z Project Lombok, która robi to samo.
Consumer
s in forEach
może być wykonywane równolegle, gdy używasz równoległych Stream
s. Rzut rzucony z odbiorcą zostanie następnie przeniesiony do wątku wywołującego, który 1) nie zatrzyma innych równolegle działających konsumentów, co może, ale nie musi być odpowiednie, oraz 2) jeśli więcej niż jeden konsument rzuci coś, tylko jeden z rzucanych przedmiotów będzie widoczny przez wzywający wątek.