我该如何处理一个我知道永远不会被抛出的IOException,以一种安全和可读的方式?

“可能出错的事情和不可能出错的事情之间的主要区别在于,当一个不可能出错的事情出错时,通常不可能得到或修复。

我有一个类文件项。FileItems 构造函数采用一个文件,如果该文件不存在,则引发异常 (FileNotFoundException)。该类的其他方法也涉及文件操作,因此能够抛出FileNotFoundException。我想找到一个更好的解决方案。一种不需要其他程序员处理所有这些极不可能的FileNotFoundExceptions的解决方案。

事实:

  1. 该文件已被检查是否存在,但极不可能存在的可能性,即通过现实的一些重大错误,该文件可能会在调用此方法之前被删除。
  2. 由于 1 发生概率与 1 的概率极不相似且不可恢复,因此我更愿意定义一个未经检查的异常。
  3. 该文件已被发现存在,迫使其他程序员编写代码并捕获检查过的FileNotFoundException似乎乏味且无用。此时,程序应该完全失败。例如,计算机总是有可能着火,但没有人会疯狂到迫使其他程序员将其作为检查异常来处理
  4. 我不时遇到这种异常问题,每次遇到此问题(我的旧解决方案)时定义自定义未经检查的异常很烦人,并且会增加代码膨胀。

代码当前如下所示

 public Iterator getFileItemsIterator() {
    try{
        Scanner sc = new Scanner(this.fileWhichIsKnowToExist);
        return new specialFileItemsIterator(sc);        
       } catch (FileNotFoundException e){ //can never happen} 

    return null;
 }

如何在不定义自定义的未选中的 FileNotFoundException 的情况下更好地执行此操作?有没有办法将 checkedException 转换为 uncheckException?


答案 1

处理此问题的常用模式是异常链接。您只需将 FileNotFoundException 包装在 RuntimeException 中:

catch(FileNotFoundException e) {
    throw new RuntimeException(e);
}

此模式不仅适用于在特定情况下(如您的情况)无法发生异常的情况,而且适用于您没有办法或无意真正处理异常的情况(如数据库链接故障)。

编辑:当心这种看起来相似的反模式,我经常在野外看到:

catch(FileNotFoundException e) {
    throw new RuntimeException(e.getMessage());
}

通过这样做,您将丢弃原始堆栈跟踪中的所有重要信息,这通常会使问题难以跟踪。

另一个编辑:正如Thorbjørn Ravn Andersen在他的回应中正确指出的那样,说明为什么在评论中或更好的是,作为异常消息来说明为什么你要链接异常并没有什么坏处:

catch(FileNotFoundException e) {
    throw new RuntimeException(
        "This should never happen, I know this file exists", e);
}

答案 2

您可以通过将已选中的异常嵌套在 RuntimException 中来将其转换为未选中的异常。如果异常在堆栈中的较高位置被捕获并使用 printStackTrace() 输出,则原始异常的堆栈也将显示。

try {
    // code...
}
catch (IOException e) {
    throw new RuntimeException(e);
}

这是一个很好的解决方案,您应该在这些情况下毫不犹豫地使用它。


推荐