Проверенные исключения, выброшенные из лямбда-выражений

Не могли бы вы объяснить, почему проверенные исключения должны быть пойманы из лямбда-выражений? Другими словами, почему следующий код не компилируется...

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)));
}
Другие вопросы по тегам