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

时间:2015-04-24 04:34:38

标签: java file exception lambda java-stream

我正在使用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
}

如您所见,方法签名声明抛出所有IOExceptions,并且流内的writeToString方法可能会抛出IOException。但是,Java编译器给出了一个错误,指出流线上存在未处理的IOException。

为什么流中的异常不会像方法中的任何其他异常一样被抛出?有没有办法在不在forEach lambda表达式中放入try-catch语句的情况下解决这个问题?

2 个答案:

答案 0 :(得分:3)

不要重新发明轮子。使用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 s),就是这样。支持addNewLine选项的障碍可以通过将String收集到一个案例中来解决,addNewLinefalse,因此,不会有换行符他们之间。否则,Files.write会将换行符附加到每个字符串。

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

更糟糕的是,无论File.exists()File.delete()File.createNewFile()可能返回,在您后续的I / O操作中已经是过时的信息,例如创建/使用Writer,并不保证后续操作是成功还是失败。

答案 1 :(得分:2)

你必须在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 - &gt; {} .Here {}表示编译器创建新的Interface(消费者)

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

并且新类实现了这个接口并将s参数传递给它的accept方法。你可以在方法中抛出新类的异常吗?不。所以你必须尝试抓住每个foreach项目