从lambda表达式中抛出的已检查异常

时间:2015-02-24 22:15:57

标签: java exception-handling lambda java-8 checked-exceptions

您能否解释为什么必须从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 个答案:

答案 0 :(得分:9)

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

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

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

请注意,accept未声明抛出任何内容。这意味着没有任何实现可以抛出任何东西;不是命名类,不是匿名类,也不是lambda。

答案 1 :(得分:5)

您的read方法似乎会抛出IOException

IntStream.forEach的签名是forEach(IntConsumer action),其中IntConsumervoid 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)));
}