Проверенные исключения, выброшенные из лямбда-выражений
Не могли бы вы объяснить, почему проверенные исключения должны быть пойманы из лямбда-выражений? Другими словами, почему следующий код не компилируется...
public void doSomething(ObjectInputStream istream) throws IOException {
// The read method throws an IOException.
IntStream.range(0, 10).forEach(i -> someList.add(read(istream)));
}
а этот будет?
public void doSomething(ObjectInputStream istream) throws IOException {
IntStream.range(0, 10).forEach(i -> {
try {
// The read method throws an IOException.
someList.add(read(istream));
}
catch (IOException ioe) {
// Callee has to handle checked exception, not caller.
}
});
}
Кажется, что вызываемый теперь должен обрабатывать любые проверенные исключения, а не вызывающий.
2 ответа
Проблема не в лямбда-выражении, а в интерфейсе, который он реализует. Помните, что лямбда-выражение - это просто сокращение для анонимного класса, который реализует данный интерфейс.
В этом случае, forEach
занимает java.util.function.Consumer<T>
:
public interface Consumer<T> {
void accept(T t);
...
}
Обратите внимание, что accept
не объявлено, чтобы бросить что-либо. Это означает, что никакая реализация этого не может бросить что-либо; не именованный класс, не анонимный класс и не лямбда.
Кажется, что ваш read
метод бросков IOException
,
Подпись IntStream.forEach
является forEach(IntConsumer action)
, где IntConsumer
имеет void accept(int value)
метод. В этом контексте ваше лямбда-выражение i -> someList.add(read(istream))
эквивалентно:
public class IntConsumerImplementation implements IntConsumer {
ObjectInputStream istream;
public void accept(int i) {
someList.add(read(istream));
};
}
который не компилируется, потому что read
выдает проверенное исключение.
С другой стороны, лямбда-выражения могут генерировать проверенные исключения, если их определяет функциональный интерфейс (что не относится к потребителям или другим java.util
функциональные интерфейсы).
Предположим следующий составленный пример:
@FunctionalInterface
public interface NotAnIntConsumer {
public void accept(int i) throws IOException;
}
Теперь следующие компиляции:
forEach(NotAnIntConsumer naic) { ... }
doSomething(ObjectInputStream istream) throws IOException {
IntStream.range(0, 10).forEach(i -> someList.add(read(istream)));
}