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

时间:2016-06-09 13:06:15

标签: java exception lambda java-8

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

for (Map.Entry<String, String> 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的快速修复建议对我来说不合适......它只是用throw块围绕try-catch语句:

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

2 个答案:

答案 0 :(得分:45)

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

public interface Map<K, V> {

    default void forEach(BiConsumer<? super K, ? super V> action) { ... }

}                        |
                         |
                         V
@FunctionalInterface
public interface BiConsumer<T, U> {

    void accept(T t, U u); // <-- does throw nothing

}

当我们谈论检查异常时,这是真的。但你仍然可以抛出一个未经检查的异常(例如java.lang.IllegalArgumentException):

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

答案 1 :(得分:25)

你可以在lambdas中抛出异常。

允许lambda抛出与lambda实现的功能接口相同的异常。

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

在您的特定情况下,kombu使用concurrent.futures.ThreadPoolExecutor作为参数,BiConsumer定义为:

Map.forEach

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

BiConsumer包中定义的功能接口中的方法不会抛出异常,但是您可以使用其他功能接口或创建自己的接口以便能够抛出异常,即给定此接口:

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

以下代码是合法的:

java.util.function