为什么 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 了解更多选择。
在下面的代码中,我在方法签名中写了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 了解更多选择。