Java List.stream.forEach Lambda 表达式中未处理的 IOException

Unhandled IOException Inside Java List.stream.forEach Lambda Expression

我正在使用 Java 8 中介绍的 Stream API 到 运行 列表中每个字符串的方法。

public boolean initFile() throws IOException
{
    if (this.outFile.exists()) {
        this.outFile.delete();
    }
    return this.outFile.createNewFile();
}

public void writeStringToFile(String str, boolean addNewLine) throws IOException
{
    if (this.mode != FileMode.READ) {
        if (this.initFile()) {
            FileWriter fileWriter;
            if (this.mode == FileMode.APPEND)
                fileWriter = new FileWriter(outFile.getAbsolutePath(), true);
            else
                fileWriter = new FileWriter(outFile.getAbsolutePath());
            fileWriter.write(str);
            if (addNewLine)
                fileWriter.write("\n");
            fileWriter.close();
        } else {
            throw new IOException("IO Error: The file could not be initialized.");
        }
    } else {
        throw new IOException("Cannot write to a file with the mode FileMode.READ");
    }
}

public void writeListToFile(List<String> strings, boolean addNewLine) throws IOException
{
    strings.stream().forEach(s -> this.writeStringToFile(s, addNewLine)); // Unhandled IOException from writeStringToFile
}

如您所见,方法签名声明抛出所有 IOException,流中的 writeToString 方法有可能抛出 IOException。然而,Java 编译器给我一个错误,指出流线上有一个未处理的 IOException。

为什么流中的异常不会像方法中的任何其他异常一样被抛出?有什么方法可以解决这个问题,而无需在 forEach lambda 表达式中放置 try-catch 语句?

你必须像这样在 writeListToFile 方法中使用 try catch:

  public void writeListToFile(List<String> strings, boolean addNewLine) throws Exception {
    strings.stream().forEach(s -> {
        try {
            writeStringToFile(s, addNewLine);
        } catch (IOException ex) {
            //you can Log it immediately or throw ex;
            Logger.getLogger(C.class.getName()).log(Level.SEVERE, null, ex);
        }
    });
    // Unhandled IOException from writeStringToFile
}

为什么? 看这一点 s -> {}。这里的 {} 表示编译器创建新的 Interface (Consumer)

 void forEach(Consumer<? super T> action);

和 new Class 实现此接口并将 s 参数传递给它接受 method.Can 您在方法中抛出 new Class 的异常? No.So 你必须尝试捕获 foreach 的每个项目

不要重新发明轮子。使用 Java API.

提供的功能
public void writeListToFile(List<String> strings, boolean addNewLine) throws IOException
{
  if(this.mode == FileMode.READ)
      throw new IOException("Cannot write to a file with the mode FileMode.READ");

  Files.write(outFile.toPath(), addNewLine? strings:
      Collections.singleton(strings.stream().collect(Collectors.joining())),
    this.mode==FileMode.APPEND? StandardOpenOption.APPEND: StandardOpenOption.CREATE);
}

Files.write 将写入 Iterable 的所有行(包括 Collection),仅此而已。您支持 addNewLine 选项的障碍可以通过将所有 String 集为一个来解决,在 addNewLinefalse 的情况下,因此不会有换行符那么他们之间。否则,Files.write 将向每个字符串附加换行符。

手动处理文件存在性测试或尝试删除或创建文件是没有意义的。无论您是创建自己的 Writer 还是使用 Files.write,这些实现都会报告有关 existence/non-existence 的失败或通过 IOExceptions 创建目标文件的失败尝试,因此您不需要自己做。

更糟糕的是,无论 File.exists()File.delete()File.createNewFile() 可能 return,在您随后的 I/O 操作中已经是过时的信息,例如creating/using一个Writer,不保证后续操作是成功还是失败。