Вопрос-ответ

Java 8 Lambda function that throws exception?

Java 8 лямбда-функция, которая выдает исключение?

Я знаю, как создать ссылку на метод, который имеет String параметр и возвращает int, это:

Function<String, Integer>

Однако это не сработает, если функция выдает исключение, скажем, оно определено как:

Integer myMethod(String s) throws IOException

Как бы я определил эту ссылку?

Переведено автоматически
Ответ 1

Вам нужно будет выполнить одно из следующих действий.


  • Если это ваш код, то определите свой собственный функциональный интерфейс, который объявляет проверяемое исключение:


    @FunctionalInterface
    public interface CheckedFunction<T, R> {
    R apply(T t) throws IOException;
    }

    и используйте ее:


    void foo (CheckedFunction f) { ... }

  • В противном случае оберните Integer myMethod(String s) в метод, который не объявляет проверяемое исключение:


    public Integer myWrappedMethod(String s) {
    try {
    return myMethod(s);
    }
    catch(IOException e) {
    throw new UncheckedIOException(e);
    }
    }

    а затем:


    Function<String, Integer> f = (String t) -> myWrappedMethod(t);

    или:


    Function<String, Integer> f =
    (String t) -> {
    try {
    return myMethod(t);
    }
    catch(IOException e) {
    throw new UncheckedIOException(e);
    }
    };

Ответ 2

Вы действительно можете расширить ConsumerFunction и т.д.) с помощью нового интерфейса, который обрабатывает исключения, используя методы по умолчанию Java 8!

Рассмотрим этот интерфейс (расширяется Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

@Override
default void accept(final T elem) {
try {
acceptThrows(elem);
} catch (final Exception e) {
// Implement your own exception handling logic here..
// For example:
System.out.println("handling an exception...");
// Or ...
throw new RuntimeException(e);
}
}

void acceptThrows(T elem) throws Exception;

}

Тогда, например, если у вас есть список:

final List<String> list = Arrays.asList("A", "B", "C");

Если вы хотите использовать ее (например, с помощью forEach) с каким-либо кодом, который генерирует исключения, вы бы традиционно настроили блок try / catch:

final Consumer<String> consumer = aps -> {
try {
// maybe some other code here...
throw new Exception("asdas");
} catch (final Exception ex) {
System.out.println("handling an exception...");
}
};
list.forEach(consumer);

Но с этим новым интерфейсом вы можете создать его экземпляр с помощью лямбда-выражения, и компилятор не будет жаловаться:

final ThrowingConsumer<String> throwingConsumer = aps -> {
// maybe some other code here...
throw new Exception("asdas");
};
list.forEach(throwingConsumer);

Или даже просто используйте ее, чтобы быть более краткой!:

list.forEach((ThrowingConsumer<String>) aps -> {
// maybe some other code here...
throw new Exception("asda");
});

Обновить

Похоже, в состав Durian входит очень хорошая служебная библиотека под названием Errors, которая может быть использована для решения этой проблемы с гораздо большей гибкостью. Например, в моей реализации выше я явно определил политику обработки ошибок (System.out... или throw RuntimeException), тогда как ошибки Durian позволяют применять политику "на лету" с помощью большого набора служебных методов. Спасибо, что поделились этим, @NedTwigg!.

Пример использования:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));
Ответ 3

Я думаю, что классErrorsDurian's сочетает в себе многие плюсы различных предложений, приведенных выше.

Чтобы включить Durian в свой проект, вы можете либо:


  • возьмите ее из jcenter или maven central по адресу com.diffplug.durian:durian:3.3.0

  • или просто скопируйте и вставьте в свой код всего два небольших класса: Throwing.java и Errors.java

Ответ 4

Это не специфично для Java 8. Вы пытаетесь скомпилировать что-то эквивалентное:

interface I {
void m();
}
class C implements I {
public void m() throws Exception {} //can't compile
}
java lambda java-8