Вы можете попробовать это:
void deleteEntity(Node node) throws SomeException { node.getChildren().forEach(UtilException.rethrowConsumer(this::deleteChild));
}
UtilException
вспомогательный класс ниже позволяет использовать любые проверяемые исключения в Java потоки. Обратите внимание, что поток выше также выбрасывает исходное проверенное исключение, созданное this::deleteChild
, и НЕ какое-либо исключение, не прошедшее проверку.
public final class UtilException {
@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
void accept(T t) throws E;
}
@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
void accept(T t, U u) throws E;
}
@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
R apply(T t) throws E;
}
@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
T get() throws E;
}
@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
void run() throws E;
}
/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
return t -> {
try { consumer.accept(t); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
return (t, u) -> {
try { biConsumer.accept(t, u); }
catch (Exception exception) { throwAsUnchecked(exception); }
};
}
/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
return t -> {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
return() -> {
try { return function.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
};
}
/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
{
try { t.run(); }
catch (Exception exception) { throwAsUnchecked(exception); }
}
/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
{
try { return supplier.get(); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
try { return function.apply(t); }
catch (Exception exception) { throwAsUnchecked(exception); return null; }
}
@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }
}
Много других примеров о том, как использовать его (после того, как статически импортирования UtilException
):
@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));
Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.forEach(rethrowConsumer(System.out::println));
}
@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
List<Class> classes1
= Stream.of("Object", "Integer", "String")
.map(rethrowFunction(className -> Class.forName("java.lang." + className)))
.collect(Collectors.toList());
List<Class> classes2
= Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
.map(rethrowFunction(Class::forName))
.collect(Collectors.toList());
}
@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
Collector.of(
rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
}
@Test
public void test_uncheck_exception_thrown_by_method() {
Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));
Class clazz2 = uncheck(Class::forName, "java.lang.String");
}
@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
Class clazz3 = uncheck(Class::forName, "INVALID");
}
Но не использовать его, прежде чем понять следующие преимущества, недостатки и ограничения:
• Если вызывающий код обрабатывает исключенное исключение, вы ДОЛЖНЫ добавить его в предложение throws метода, содержащего поток. Компилятор не заставит вас добавить его больше, поэтому его легче забыть.
• Если код вызова уже обрабатывает проверенное исключение, компилятор НАСТОЯТЕЛЬНО напоминает вам добавить предложение throws к объявлению метода , содержащему поток (если вы этого не скажете: исключение никогда не выбрасывается тело соответствующего утверждения try).
• В любом случае вы не сможете окружить поток, чтобы поймать исключенное исключение. INSIDE метод, содержащий поток (если вы попытаетесь, компилятор скажет: Исключение никогда не выбрасывается в тело соответствующий запрос try).
• Если вы вызываете метод, который буквально никогда не может генерировать исключение, которое он объявляет, тогда вы не должны включать предложение throws. Например: new String (byteArr, «UTF-8») выбрасывает UnsupportedEncodingException, но UTF-8 гарантируется спецификацией Java всегда присутствовать. Здесь объявление бросков является неудобством, и любое решение, чтобы заставить его замолчать с минимальным шаблоном, приветствуется.
• Если вы ненавидите проверенные исключения и чувствуете, что их никогда не следует добавлять к языку Java (все больше людей думают так, и я НЕ один из них), то просто не добавляйте проверенное исключение в предложение throws метода, содержащего поток. Исключенное исключение будет вести себя так же, как исключение Unchecked.
• Если вы реализуете строгий интерфейс, в котором у вас нет возможности добавить объявление бросков, но при этом исключение составляет , то это необходимо для исключения исключения, чтобы получить привилегию бросить его в результате stacktrace с ложными исключениями, которые не сообщают никакой информации о том, что на самом деле пошло не так. Хорошим примером является Runnable.run(), который не бросает никаких проверенных исключений. В этом случае вы можете не добавлять исключенное исключение в предложение throws метода, содержащего поток.
• В любом случае, если вы решили не добавлять (или забыл добавить) проверенное исключение бросков пункта метода, который содержит поток, быть в курсе этих 2 последствий метания проверяемых исключений:
1) Код вызова не сможет поймать его по имени (если вы попробуете, компилятор скажет: «Исключение никогда не выбрасывается в тело соответствующего запроса »). Он будет пузыриться и, вероятно, попадает в основной программный цикл с помощью некоторых «исключений catch» или «catch Throwable», которые могут быть тем, что вы в любом случае хотите получить .
2) Он нарушает принцип наименьшего удивления: его больше не будет хватать, чтобы поймать RuntimeException, чтобы иметь возможность гарантировать, что вы поймаете все возможных исключений. По этой причине я считаю, что этого не следует делать в коде кода, но только в бизнес-коде, который вы полностью контролируете.
В заключение: Я считаю, что ограничения здесь несерьезны, и класс UtilException
может использоваться без страха. Но это зависит от вас!
В стороне, это не выражение лямбда - это ссылка на метод. Это выражение было бы lambda, если бы вы использовали 'forEach (x -> deleteChild (x))'. Однако это пойдет по той же причине. –