Java 如何廉洁地处理;未报告的异常IOException“;在流/forEach?

Java 如何廉洁地处理;未报告的异常IOException“;在流/forEach?,java,compiler-errors,java-8,java-stream,Java,Compiler Errors,Java 8,Java Stream,我正在尝试使用Java流写入文件。据我所知,只要你将异常抛出,就不必捕捉异常。 但是,编译器抛出一个错误(在stream.foreach()的行上),并说 错误:未报告的异常IOException;必须被抓住或宣布被抛出 有人能解释一下为什么会这样吗? (我只对使用流的解决方案感兴趣) public void save(字符串文件、ArrayList文本)引发IOException{ FileWriter fw=新的FileWriter(文件); text.stream().forEach(x-

我正在尝试使用Java流写入文件。据我所知,只要你将异常抛出,就不必捕捉异常。 但是,编译器抛出一个错误(在stream.foreach()的行上),并说

错误:未报告的异常IOException;必须被抓住或宣布被抛出

有人能解释一下为什么会这样吗? (我只对使用流的解决方案感兴趣)

public void save(字符串文件、ArrayList文本)引发IOException{
FileWriter fw=新的FileWriter(文件);
text.stream().forEach(x->fw.write(x+“\n”);
fw.close();
}
Netbeans提出了这一点,但有没有更简单的方法

public void save(String file, ArrayList<String> text) throws IOException {
    FileWriter fw = new FileWriter(file);
    text.stream().forEach(x->{
        try {
            fw.write(x +"\n");
        } catch (IOException ex) {
            ...
        }
    });
    fw.close();
}
public void save(字符串文件、ArrayList文本)引发IOException{
FileWriter fw=新的FileWriter(文件);
text.stream().forEach(x->{
试一试{
fw.写入(x+“\n”);
}捕获(IOEX异常){
...
}
});
fw.close();
}

不幸的是,没有简单的解决方案。需要捕获抛出选中异常的Lambda表达式。最简单的方法可能是在单独的方法中将选中的异常转换为未选中的异常

try {
    text.forEach(this::write);
catch (UncheckedIOException ex) {
    ...
}

private void write(String line) throws UncheckedIOException {
    try {
        fw.write(line +"\n");
    } catch (IOException ex) {
        throw new UncheckedIOException(ex);
    }
});
不过,老实说,除了让
save
方法更干净之外,这并没有比NetBean的建议更整洁

如果您不清楚选中/未选中异常的区别,请阅读接受的答案


请注意,
List
有一个
forEach
方法(实际上是
Iterable
扩展的
List
方法),因此
stream()
是多余的。

forEach
操作需要一个
消费者,其
accept
方法不允许抛出选中的异常。在您的情况下,解决方案很简单:

public void save(String file, ArrayList<String> text) throws IOException {
    Files.write(Paths.get(file), text, Charset.defaultCharset());
}
你可以像这样使用它

public void save(String file, ArrayList<String> text) throws IOException {
    try( FileWriter fw = new FileWriter(file) ) {
        IOConsumer.doForEach(text.stream(), x -> fw.write(x +"\n"));
    }
}
public void save(字符串文件、ArrayList文本)引发IOException{
try(FileWriter fw=newfilewriter(文件)){
IOConsumer.doForEach(text.stream(),x->fw.write(x+“\n”);
}
}
此构造确保您在启动器级别正确处理潜在的
IOException
s。注意,我用正确的try with resource构造替换了不安全的显式
close()
调用


有了它,您仍然可以使用任意的中间流操作,即
doForEach(text.stream().intermediateOp1().iOp2(),x->fw.write(x+“\n”)
或集合以外的流源。

这是一个非常恼人的问题,我认为没有较短的解决方案。我的答案基本上包含了友好狗的答案。除了
runtimeexecptions
@Thorvason之外,你不能忽略任何东西,这是不正确的。您还可以忽略
Error
的子类。参见
UncheckedIOException
应包括原始原因:
抛出新的UncheckedIOException(ex)。或者,您可以
抛出ex
将异常简单地传播到调用堆栈中。在这种情况下,后面的选择似乎是合理的,因为
save()
已经用
抛出IOException
@code学徒谢谢-很好的捕获。你的意思是
中抛出ex
?这是行不通的,因为它抛出了一个未选中的ex,并且ex被选中了。在最初发布该评论后,我对其进行了多次编辑。不确定您是否看到了最新版本。我认为,
抛出ex更可取,因为
save()
已经有了一个合适的
throws
子句。按照我阅读OP的方式,最初的问题源于lambda表达式,而不是一般的
throws
子句。
public void save(String file, ArrayList<String> text) throws IOException {
    Files.write(Paths.get(file),
                (Iterable<String>)()->text.stream().iterator(), Charset.defaultCharset());
}
interface IOConsumer<T> extends Consumer<T> {
    public default void accept(T t) {
        try { doIO(t); } catch(IOException ex) { throw new UncheckedIOException(ex); }
    }
    void doIO(T t) throws IOException;

    public static <E> void doForEach(Stream<? extends E> s, IOConsumer<? super E> c)
    throws IOException {
        try{ s.forEachOrdered(c); } catch(UncheckedIOException ex){ throw ex.getCause(); }
    }
}
public void save(String file, ArrayList<String> text) throws IOException {
    try( FileWriter fw = new FileWriter(file) ) {
        IOConsumer.doForEach(text.stream(), x -> fw.write(x +"\n"));
    }
}