我升级到Java 8,并试图用新的lamdba表达式替换通过Map的简单迭代。循环搜索 null 值,如果找到异常,则引发异常。旧的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 的快速修复建议对我来说看起来不对......它只是用try-catch
块包围throw
语句:
myMap.forEach((k,v) -> {
if(v == null) {
try {
throw new MyException("Key '" + k + "' not found!");
}
catch (Exception e) {
e.printStackTrace();
}
}
});
引发选中的异常,因为 java.util.function.BiConsumer<T, U>
接口中的 accept(T t, U 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(); });
您可以在 lambda 中抛出异常。
允许 lambda 引发与 lambda 实现的功能接口相同的异常。
如果函数接口的方法没有 throws 子句,则 lambda 无法抛出 CheckedExceptions。(您仍然可以抛出运行时异常)。
在您的特定情况下,Map.forEach
使用 BiConsumer
作为参数,BiConsumer 定义为:
public interface BiConsumer<T, U> {
void accept(T t, U u);
}
此函数接口的 lambda 表达式不能抛出 CheckedExceptions。
包中定义的函数接口中的方法不会抛出异常java.util.function
但您可以使用其他函数接口或创建自己的函数接口来抛出异常,即给定此接口:
public interface MyFunctionalInterface<T> {
void accept(T t) throws Exception;
}
以下代码是合法的:
MyFunctionalInterface<String> f = (s)->throw new Exception("Exception thrown in lambda");