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

似乎被调用者现在必须处理抛出的任何检查异常,而不是调用者。

4

2 回答 2

9

问题不在于 lambda 表达式,而在于它正在实现的接口。请记住,lambda 表达式基本上只是实现给定接口的匿名类的简写。

在这种情况下,forEach需要一个java.util.function.Consumer<T>

public interface Consumer<T> {
    void accept(T t);
    ...
}

请注意,accept没有声明抛出任何东西。这意味着它的任何实现都不会抛出任何东西;不是命名类,不是匿名类,也不是 lambda。

于 2015-02-24T22:30:53.897 回答
5

看来您的read方法会抛出IOException.

IntStream.forEachis的签名forEach(IntConsumer action),其中IntConsumer有一个void accept(int value)方法。在这种情况下,您的 lambda 表达式i -> someList.add(read(istream))等效于:

public class IntConsumerImplementation implements IntConsumer {
   ObjectInputStream istream;
   public void accept(int i) {
      someList.add(read(istream));
   };
}

它不会编译,因为read会引发检查异常。

另一方面,如果函数式接口定义了 lambda 表达式,则它们可能会抛出已检查异常(消费者或其他函数式接口并非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)));
}
于 2015-02-24T22:36:40.043 回答