为什么 Lambda 不理解方法签名中的抛出?

Why doesn't Lambda understand throws in method signature?

在下面的代码中,我在方法签名中写了throws,但是在Lambda中再次为write,编译器报错。为什么?

编译器错误:未处理的异常:java.io.IOException

 public void saveTodoItems() throws IOException {

    try (BufferedWriter outputStream = new BufferedWriter(new OutputStreamWriter(
            new FileOutputStream("TodoItems.txt"), StandardCharsets.UTF_8))) {

        todoItems.forEach(todoItem -> {
                outputStream.write(todoItem.getShortDescription() + "\t" //compile error on write
                        + todoItem.getDetail() + "\t"
                        + todoItem.getDeadLine()+"\n");

        });
    }
}

请记住,lambda 应该是功能接口的实现。在这种情况下,forEach takes the functional interface Consumer<T> 作为参数。

void forEach(Consumer<? super T> action)

所以您的 lambda 实际上是在 Consumer 接口中实现单个抽象方法 - accept。此方法未声明抛出任何异常:

void accept(T t); // no throws clause here at all!

因此,write 调用可能抛出的 IOException 被认为是未处理的。您在 saveTodoItems 方法中添加了 throws 子句这一事实是无关紧要的。

另一方面,如果您声明了自己的功能接口,并且在其单个抽象方法中确实有一个 throws 子句:

interface IOConsumer<T> {
    void accept(T t) throws IOException;
}

可以这样写:

IOConsumer<TodoItem> consumer = todoItem -> {
    outputStream.write(todoItem.getShortDescription() + "\t"
                    + todoItem.getDetail() + "\t"
                    + todoItem.getDeadLine()+"\n");
};

当然,您不能在 forEach 中使用它,因为它只接受 Consumer,而不接受 IOConsumer。您应该用 try...catch 包围 write,或者查看 here 了解更多选择。