为什么我必须在提供 lambda 参数时捕获异常?

Why must I catch exceptions when providing lambda argument?

考虑以下示例:

public class LambdaArgsTest {
    private static void display(Supplier<?> arg) {
        try {
            // this is the place where the Exception("wrong") might be thrown
            // and it is in fact handled
            System.out.println(arg.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        display(() -> {
            if(/*some condition*/) {
                // this statement will be rejected due to unhandled exception
                throw new Exception("wrong");
            }
            return "abcde";
        });
    }
}

问题来了:上例中的lambda参数是一个对象,稍后将在“display()”方法中执行。将参数传递给“display()”时显然没有执行。

为什么会被编译器拒绝?我认为只有在实际调用lambda时才用try...catch包围它是很合理的。

这是因为Supplier功能接口的签名:

T get();

如您所见,方法 get 未声明为抛出 Exception(也没有任何其他 checked 异常)。

在Java中,有checked vs unchecked异常(未检查的异常是那些继承自RuntimeException).必须处理已检查的异常,方法是在 catch 块中捕获它们,或者通过声明方法 throws 该异常。

如果 Supplier.get 的签名是:

T get() throws Exception:

代码可以正常编译。

尝试抛出 RuntimeException 而不是 Exception 并且代码可以正常编译。


编辑: 根据 Peter Lawrey 在评论中的建议,如果您确实需要从 lambda 表达式中抛出检查异常,您可以使用例如Callable,其唯一一个方法的签名如下:

T call() throws Exception;

您只需要将 Callable 传递给您的 display 方法而不是 Supplier.