为什么Files.list
会抛出IOException
,而File.listFiles
却没有?
查看Files.list
(Java 8)的源代码,我更加好奇为什么没有抛出UncheckedIOException
因为它也被抛入迭代器中。
如果我用File.listFiles
替换Files.list
- 代码,我现在需要处理一个我之前没有真正处理过的异常。
毋庸置疑,大多数开发人员甚至不知道他们在那时需要处理什么;-)或者只是在那里放// TODO
和/或e.printStackTrace()
。
这使Stream
在这里使用相当麻烦,因为你需要用try/catch
包围它或重新抛出异常,这在遗留代码中甚至是不可能的。
那么为什么要做出这个决定?
答案 0 :(得分:6)
首先,开发人员总是必须处理可能发生的错误情况。
如果此抽象路径名不表示目录,或者发生I / O错误,则返回
null
。
抛出:
NotDirectoryException
- 如果文件无法打开,因为它不是目录(可选的特定例外)IOException
- 如果在打开目录时发生I / O错误
所以区别在于开发人员可能很容易忘记null
的检查,只要没有错误的情况就不会注意到。{1}}。当问题发生在客户身上并且您的应用程序抛出NullPointerException
而不是处理可能微不足道的问题时,您将以艰难的方式学习它。
你的陈述“毋庸置疑,大多数开发人员甚至不知道他们在那时需要处理什么”。确实,但编译器会在编译时告诉你,你必须处理IOException
。与File.list()
不同,可能会忽略检查null
的失败。你仍然可以在的任何一种情况下处理它,但是没有办法阻止这种情况。
当然,一旦你明白你必须处理这个问题,你可能会问你想要如何处理它,这取决于问题的类型。返回值为null
并不会告诉您有关此问题的任何信息。您可以通过File.isDirectory()
检查“不是目录”条件并希望它之间没有变化,但如果文件是目录,则您没有提示从哪里开始。
相反,抛出的IOException
不仅允许您区分NotDirectoryException
和其他错误条件,IOException
是特定异常林的基类,可以精确地描述问题,例如AccessDeniedException
。即使异常具有非特定类型,它也可能具有有意义的消息,您可以向用户显示。
请注意,这是使用这两个API的一般模式:
返回:
true
当且仅当重命名成功时;false
否则
返回:
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
之前的行为(如果您曾在旧代码中检查过),可能确实很麻烦,但这不是处理此类情况的预期方法,那么为什么应该这样舒服......