java.io.File.listFiles vs java.nio.Files.list及其引发的IOException

java.io.File.listFiles vs java.nio.Files.list及其引发的IOException,java,java-8,java-stream,nio,java-io,Java,Java 8,Java Stream,Nio,Java Io,为什么Files.list抛出一个IOException,而File.listFiles没有 查看Files.list(Java8)的源代码,我更好奇的是为什么没有抛出未选中的异常,因为它也是在迭代器中抛出的 如果我将File.listFiles-code替换为Files.list,我现在需要处理一个以前没有处理过的异常。 不用说,大多数开发人员甚至不知道在那个时候他们必须处理什么;-)或者在那里放一个//TODO和/或e.printStackTrace() 这使得在这里使用流相当麻烦,因为您需

为什么
Files.list
抛出一个
IOException
,而
File.listFiles
没有

查看
Files.list
(Java8)的源代码,我更好奇的是为什么没有抛出
未选中的异常,因为它也是在迭代器中抛出的

如果我将
File.listFiles
-code替换为
Files.list
,我现在需要处理一个以前没有处理过的异常。 不用说,大多数开发人员甚至不知道在那个时候他们必须处理什么;-)或者在那里放一个
//TODO
和/或
e.printStackTrace()

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


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

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

  • :

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

  • :

    抛出:

    • NotDirectoryException
      -如果文件不是目录而无法打开(可选特定异常)
    • IOException
      -如果在打开目录时发生I/O错误
因此,区别在于开发人员可能很容易忘记检查
null
,只要没有错误的条件,就永远不会注意到这一点。当问题发生在客户身上,应用程序抛出一个
NullPointerException
而不是处理一个可能微不足道的问题时,您将以一种艰难的方式了解到这一点

您的陈述“不用说,大多数开发人员甚至不知道他们在那个时候需要处理什么”,就很好地说明了这一点。的确,但是编译器会在编译时告诉您,您必须处理
IOException
。与
File.list()
不同,在
File.list()中,可以忽略检查
null
的失败。在这两种情况下,你都可能处理得不好,但没有办法防止这种情况发生

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

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

请注意,这是这两个API的通用模式:

  • 返回:
    true
    当且仅当重命名成功时<代码>错误
否则

  • 返回:
    true
    当且仅当成功删除文件或目录时<代码>错误
  • 否则

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

    • 抛出:

      • fileReadyExistsException
        -如果目标文件存在但无法替换,因为未指定
        REPLACE\u EXISTING
        选项(可选特定异常)
      • DirectoryNotEmptyException
        -指定了
        REPLACE\u EXISTING
        选项,但无法替换该文件,因为它是非空目录(可选的特定异常)
        AtomicMoveNotSupportedException
        -如果选项数组包含
        原子移动
        选项,但文件不能作为原子文件系统操作移动
      • IOException
        -如果发生I/O错误
    这就是我所说的帮助

    • 抛出:
      • NoSuchFileException
        -如果文件不存在(可选特定异常)
      • DirectoryNotEmptyException
        -如果文件是一个目录,并且由于目录不为空而无法删除(可选的特定异常)
      • IOException
        -如果发生I/O错误
    同样,这比布尔值更有用。但请注意,还有一个,如果你想非异常地处理一个琐碎的条件。由于所有其他非平凡条件仍然作为异常处理,所以不能混淆它们

    当然,API设计者可以使用未经检查的异常,但这会导致什么呢

    这使得在这里使用流相当麻烦,因为您需要用try/catch或rethrow异常来包围它,这在遗留代码中甚至是不可能的

    没错。您可以更改从未引发此类异常的代码(因为在错误的情况下,
    File.list()
    返回
    null
    ),以调用可能引发未检查异常的新方法,因为这“在旧代码中是可能的”-但旧调用方不期望该异常,也不会处理它


    捕获异常并像以前一样执行返回的
    null
    (如果您在旧代码中检查过的话),可能确实很麻烦,但这不是处理此类情况的预期方法,所以为什么要让它变得舒适…

    同意。对于错误的情况,应采取适当的措施加以处理