Я высоко ценю новые функции Java 8, касающиеся лямбд и интерфейсов методов по умолчанию. Тем не менее, я все еще скучаю с проверенными исключениями. Например, если я просто хочу перечислить все видимые поля объекта, я хотел бы просто написать это:
Arrays.asList(p.getClass().getFields()).forEach(
f -> System.out.println(f.get(p))
);
Тем не менее, поскольку get
метод может выдать проверенное исключение, которое не согласуется с Consumer
контрактом интерфейса, я должен перехватить это исключение и написать следующий код:
Arrays.asList(p.getClass().getFields()).forEach(
f -> {
try {
System.out.println(f.get(p));
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
);
Однако в большинстве случаев я просто хочу, чтобы исключение было сгенерировано как a RuntimeException
и позволяло программе обрабатывать или нет исключение без ошибок компиляции.
Таким образом, я хотел бы иметь свое мнение о моем спорноге для обхода проверяемых исключений раздражения. Для этого я создал вспомогательный интерфейс ConsumerCheckException<T>
и служебную функцию rethrow
( обновленную в соответствии с предложением комментария Довала ) следующим образом:
@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;
}
}
И теперь я могу просто написать:
Arrays.asList(p.getClass().getFields()).forEach(
rethrow(f -> System.out.println(f.get(p)))
);
Я не уверен, что это лучшая идиома для обхода проверенных исключений, но, как я объяснил, я хотел бы иметь более удобный способ достижения моего первого примера, не имея дело с проверенными исключениями, и это более простой способ, который я нашел сделать это.
sneakyThrow
внутри, rethrow
чтобы бросить исходное, проверенное исключение вместо того, чтобы обернуть его в RuntimeException
. В качестве альтернативы вы можете использовать @SneakyThrows
аннотацию от Project Lombok, которая делает то же самое.
Consumer
s in forEach
может выполняться параллельно при использовании параллельных Stream
s. Затем отбрасываемое значение, вызванное отказом от потребителя, будет распространяться на вызывающий поток, который 1) не остановит других одновременно работающих потребителей, что может или не может быть уместно, и 2) если более одного из потребителей что-то выбрасывают, только одна из меток будет видна вызывающему потоку.