来自lambda表达式的已检查异常

6
请问为什么在lambda表达式中必须捕获已检查异常?换句话说,为什么以下代码无法编译...
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个回答

10
问题不在于 lambda 表达式本身,而是它所实现的接口。记住,lambda 表达式基本上只是一个匿名类的缩写形式,该类实现了给定的接口。
在这种情况下,forEach 接受一个 java.util.function.Consumer<T>:
public interface Consumer<T> {
    void accept(T t);
    ...
}

请注意,accept 没有声明抛出任何异常。这意味着它的所有实现都不能抛出任何异常;不是一个命名类、也不是匿名类或者 lambda。

5
It seems that your read method throws an IOException.
The IntStream.forEach function signature is forEach(IntConsumer action), and the IntConsumer interface includes a void accept(int value) method. In this context, your lambda expression i -> someList.add(read(istream)) is equivalent to:
public class IntConsumerImplementation implements IntConsumer {
   ObjectInputStream istream;
   public void accept(int i) {
      someList.add(read(istream));
   };
}

由于 read 抛出一个已检查的异常,下面这段代码无法编译。

另一方面,如果函数式接口定义了已检查的异常(对于消费者或其他 java.util 函数式接口并非如此),lambda 表达式可能会抛出这些异常。

假设以下是一个虚构的示例:

 @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)));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接