为什么我不能在Java 8 lambda表达式中抛出exception?

我升级到Java 8并试图用一个新的lamdba表达式替换一个简单的迭代迭代。 循环搜索空值并在找到exception时抛出exception。 旧的Java 7代码如下所示:

for (Map.Entry entry : myMap.entrySet()) { if(entry.getValue() == null) { throw new MyException("Key '" + entry.getKey() + "' not found!"); } } 

我将其转换为Java 8的尝试如下所示:

 myMap.forEach((k,v) -> { if(v == null) { // OK System.out.println("Key '" + k+ "' not found!"); // NOK! Unhandled exception type! throw new MyException("Key '" + k + "' not found!"); } }); 

任何人都可以解释为什么这里不允许throw语句以及如何纠正这个问题?

Eclipse的快速修复建议看起来不对我…它只是用try-catch块包围throw语句:

 myMap.forEach((k,v) -> { if(v == null) { try { throw new MyException("Key '" + k + "' not found!"); } catch (Exception e) { e.printStackTrace(); } } }); 

不允许抛出已检查的exception,因为java.util.function.BiConsumer接口中的accept(T t, U u)方法未在其throws子句中声明任何exception。 而且,如您所知, Map#forEach采用这种类型。

 public interface Map { default void forEach(BiConsumer action) { ... } } | | V @FunctionalInterface public interface BiConsumer { void accept(T t, U u); // <-- does throw nothing } 

当我们谈论检查exception时,情况就是如此。 但是你仍然可以抛出一个未经检查的exception(例如java.lang.IllegalArgumentException ):

 new HashMap() .forEach((a, b) -> { throw new IllegalArgumentException(); }); 

你可以在lambdas中抛出exception。

允许lambda抛出与lambda实现的function接口相同的exception。

如果函数接口的方法没有throws子句,则lambda不能抛出CheckedExceptions。 (你仍然可以抛出RuntimeExceptions)。


在您的特定情况下, Map.forEach使用BiConsumer作为参数,BiConsumer定义为:

 public interface BiConsumer { void accept(T t, U u); } 

此function接口的lambda表达式不能抛出CheckedExceptions。


java.util.function包中定义的函数接口中的方法不会抛出exception,但是您可以使用其他function接口或创建自己的接口以便能够抛出exception,即给定此接口:

 public interface MyFunctionalInterface { void accept(T t) throws Exception; } 

以下代码是合法的:

 MyFunctionalInterface f = (s)->throw new Exception("Exception thrown in lambda");