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

Posted

技术标签:

【中文标题】从 lambda 表达式中抛出的已检查异常【英文标题】:Checked exceptions thrown from within lambda expressions 【发布时间】:2015-04-26 18:18:46 【问题描述】:

您能否解释一下为什么必须从 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.
    
  );

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

【问题讨论】:

【参考方案1】:

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

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

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

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

【讨论】:

【参考方案2】:

您的read 方法似乎抛出了IOException

IntStream.forEach 的签名是forEach(IntConsumer action),其中IntConsumer 有一个void accept(int value) 方法。在这种情况下,您的 lambda 表达式 i -&gt; 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)));

【讨论】:

以上是关于从 lambda 表达式中抛出的已检查异常的主要内容,如果未能解决你的问题,请参考以下文章

如果在“等待”之后抛出,则从任务中抛出的异常被吞下

Java 8 lambda表达式

Java8--Lambda表达式

如何捕获ctypes中抛出的异常?

如何捕获 node_modules 中抛出的异常

忽略在 C# .NET 中抛出的特定异常