java.io.File.listFiles vs java.nio.Files.list及其抛出的IOException

时间:2017-03-17 16:27:33

标签: java java-8 java-stream nio java-io

为什么Files.list会抛出IOException,而File.listFiles却没有?

查看Files.list(Java 8)的源代码,我更加好奇为什么没有抛出UncheckedIOException因为它也被抛入迭代器中。

如果我用File.listFiles替换Files.list - 代码,我现在需要处理一个我之前没有真正处理过的异常。 毋庸置疑,大多数开发人员甚至不知道他们在那时需要处理什么;-)或者只是在那里放// TODO和/或e.printStackTrace()

这使Stream在这里使用相当麻烦,因为你需要用try/catch包围它或重新抛出异常,这在遗留代码中甚至是不可能的。

那么为什么要做出这个决定?

1 个答案:

答案 0 :(得分:6)

首先,开发人员总是必须处理可能发生的错误情况。

  • File.list()

      

    如果此抽象路径名不表示目录,或者发生I / O错误,则返回null

  • Files.list(Path)

      

    抛出:

         
        
    • NotDirectoryException - 如果文件无法打开,因为它不是目录(可选的特定例外)
    •   
    • IOException - 如果在打开目录时发生I / O错误
    •   

所以区别在于开发人员可能很容易忘记null的检查,只要没有错误的情况就不会注意到。{1}}。当问题发生在客户身上并且您的应用程序抛出NullPointerException而不是处理可能微不足道的问题时,您将以艰难的方式学习它。

你的陈述“毋庸置疑,大多数开发人员甚至不知道他们在那时需要处理什么”。确实,但编译器会在编译时告诉你,你必须处理IOException。与File.list()不同,可能会忽略检查null的失败。你仍然可以在的任何一种情况下处理它,但是没有办法阻止这种情况。

当然,一旦你明白你必须处理这个问题,你可能会问你想要如何处理它,这取决于问题的类型。返回值为null并不会告诉您有关此问题的任何信息。您可以通过File.isDirectory()检查“不是目录”条件并希望它之间没有变化,但如果文件目录,则您没有提示从哪里开始。

相反,抛出的IOException不仅允许您区分NotDirectoryException和其他错误条件,IOException是特定异常林的基类,可以精确地描述问题,例如AccessDeniedException。即使异常具有非特定类型,它也可能具有有意义的消息,您可以向用户显示。

请注意,这是使用这两个API的一般模式:

  • File.renameTo(File)

      返回:      

    true当且仅当重命名成功时; false否则

  • File.delete()

      返回:      

    true当且仅当文件或目录被成功删除时; false否则

那么当这些方法中的任何一个返回false时,你会怎么做?

  • Files.move(Path,Path,CopyOption...)

      抛出:      

    ...

         
        
    • FileAlreadyExistsException - 如果目标文件存在但由于未指定REPLACE_EXISTING选项而无法替换(可选的特定例外)
    •   
    • DirectoryNotEmptyException - 指定了REPLACE_EXISTING选项,但无法替换该文件,因为它是非空目录(可选的特定异常)   AtomicMoveNotSupportedException - 如果options数组包含ATOMIC_MOVE选项,但该文件无法作为原子文件系统操作移动。
    •   
    • IOException - 如果发生I / O错误
    •   

这就是我所说的有用......

  • Files.delete(Path)
      抛出:      
        
    • NoSuchFileException - 如果文件不存在(可选的特定例外)
    •   
    • DirectoryNotEmptyException - 如果文件是目录,否则无法删除,因为该目录不为空(可选特定例外)
    •   
    • IOException - 如果发生I / O错误
    •   

同样,比boolean更有帮助。但请注意,还有boolean deleteIfExists(Path),以防您想要非特殊地处理这一个微不足道的情况。由于所有其他非平凡条件仍然作为例外处理,因此您不能混淆它们。

当然,API设计人员可能会使用未经检查的异常,但这会导致什么?

  

这使得在这里使用Stream相当麻烦,因为你需要用try / catch包围它或者重新抛出异常,这在遗留代码中甚至是不可能的。

完全。您将更改从未抛出此类异常的代码(因为File.list()在错误的情况下返回null)来调用可能抛出未经检查的异常的新方法,因为这“可能在遗留代码中” - 但是传统调用者不期望该异常,也永远不会处理它。

捕获异常并且在返回null之前的行为(如果您曾在旧代码中检查过),可能确实很麻烦,但这不是处理此类情况的预期方法,那么为什么应该这样舒服......