了解 Java 中的已检查异常与未选中异常

Joshua Bloch在“Effective Java”中说:

对可恢复条件使用已检验的异常,对编程错误使用运行时异常(第 2 版中的项目 58)

让我们看看我是否正确地理解了这一点。

以下是我对已检查异常的理解:

try{
    String userInput = //read in user input
    Long id = Long.parseLong(userInput);
}catch(NumberFormatException e){
    id = 0; //recover the situation by setting the id to 0
}

1. 上述情况是否被视为已检查的例外情况?

2. 运行时异常是未经检查的异常吗?

以下是我对未经检查的异常的理解:

try{
    File file = new File("my/file/path");
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){

//3. What should I do here?
    //Should I "throw new FileNotFoundException("File not found");"?
    //Should I log?
    //Or should I System.exit(0);?
}

4.现在,上面的代码不能也是一个检查异常吗?我可以尝试恢复这样的情况吗?我可以吗?(注意:我的第三个问题在上面)catch

try{
    String filePath = //read in from user input file path
    File file = new File(filePath);
    FileInputStream fis = new FileInputStream(file);   
}catch(FileNotFoundException e){
    //Kindly prompt the user an error message
    //Somehow ask the user to re-enter the file path.
}

5. 人们为什么这样做?

public void someMethod throws Exception{

}

他们为什么让异常冒泡?更快地处理错误不是更好吗?为什么要冒泡?

6. 我应该冒泡确切的异常还是使用异常来掩盖它?

以下是我的阅读材料

在 Java 中,何时应创建已检验的异常,何时应将其设置为运行时异常?

何时选择选中和未选中的例外


答案 1

许多人说,根本不应该使用选中的异常(即你应该显式捕获或重新删除的那些)。例如,它们在C#中被淘汰,大多数语言都没有它们。因此,您始终可以抛出 (未选中的异常) 的子类RuntimeException

但是,我认为检查的异常很有用 - 当您想要强制API的用户考虑如何处理异常情况(如果可以恢复)时,会使用它们。只是检查的异常在Java平台中被过度使用,这让人们讨厌它们。

以下是我对这个话题的扩展观点

至于具体问题:

  1. NumberFormatException 是否考虑已检查的异常?
    不。 未选中 (= 是 的子类 )。为什么?我不知道。(但应该有一种方法NumberFormatExceptionRuntimeExceptionisValidInteger(..))

  2. 运行时异常是未经检查的异常吗?
    是的,没错。

  3. 我在这里该怎么办?
    这取决于此代码的位置以及您希望发生的情况。如果它在UI层中 - 捕获它并显示警告;如果它在服务层中 - 根本不要抓住它 - 让它冒泡。只是不要吞下例外。如果在大多数情况下发生异常,则应选择以下选项之一:

    • 记录并返回
    • 重新抛出它(声明它是由方法抛出的)
    • 通过在构造函数中传递当前异常来构造新的异常
  4. 现在,上面的代码难道不是一个检查的例外吗?我可以尝试恢复这样的情况吗?我可以吗?
    本来是可以的。但是,没有什么能阻止您捕获未经检查的异常

  5. 为什么人们在 throws 子句中添加类 Exception
    最常见的是因为人们懒得考虑要抓住什么和要重新抛出什么。投掷是一种不好的做法,应该避免。Exception

唉,没有一个规则可以让你确定何时捕获,何时重新删除,何时使用已检查以及何时使用未选中的例外。我同意这会导致很多混乱和很多糟糕的代码。布洛赫阐述了一般原则(你引用了其中的一部分)。一般原则是将异常重新抛给可以处理它的层。


答案 2

某些内容是否是“已检查的异常”与你是否捕获它或你在 catch 块中执行的操作无关。它是异常类的属性。任何作为 except 及其子类的子类的任何内容都是已检查的异常。ExceptionRuntimeException

Java 编译器强制您捕获选中的异常或在方法签名中声明这些异常。它应该提高程序安全性,但大多数人的意见似乎是不值得它造成的设计问题。

他们为什么让异常冒泡?处理错误不是越快越好吗?为什么要冒泡?

因为这就是例外的全部意义。如果没有这种可能性,您将不需要例外。它们使您能够在您选择的级别处理错误,而不是强迫您在最初发生错误时以低级方法处理它们。