约书亚·布洛赫在《有效的Java》中说过

为以下情况使用检查异常 可恢复条件和运行时 编程错误的例外 (第二版第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. RuntimeException是未检查的异常吗?

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

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. 现在,上面的代码不能也是一个受控异常吗?我可以试着挽回这样的局面吗?我可以吗?(注:我的第三个问题在上面的陷阱里)

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中,什么时候应该创建检查异常,什么时候应该是运行时异常?

何时选择已检查异常和未检查异常


当前回答

已检查-容易发生。在编译时选中。

小薇。FileOperations

未检查-由于不良数据。在运行时签入。

如. .

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

这里的异常是由于错误的数据,在编译时无法确定。

其他回答

这里有一个简单的规则可以帮助你做出决定。它与Java中如何使用接口有关。

以你的类为例,想象一下为它设计一个接口,该接口描述类的功能,但不描述底层实现(接口应该这样)。假设您可能以另一种方式实现该类。

查看接口的方法,并考虑它们可能抛出的异常:

如果方法可以抛出异常,而不管底层实现是什么(换句话说,它只描述功能),那么它可能应该是接口中的受控异常。

如果异常是由底层实现引起的,那么它不应该出现在接口中。因此,它必须是类中的未检查异常(因为未检查异常不需要出现在接口签名中),或者必须将其包装并作为接口方法的一部分的已检查异常重新抛出。

To decide if you should wrap and rethrow, you should again consider whether it makes sense for a user of the interface to have to handle the exception condition immediately, or the exception is so general that there is nothing you can do about it and it should propagate up the stack. Does the wrapped exception make sense when expressed as functionality of the new interface you are defining or is it just a carrier for a bag of possible error conditions that could also happen to other methods? If the former, it might still be a checked exception, otherwise it should be unchecked.

通常不应该计划“冒泡”异常(捕获并重新抛出)。异常要么应该由调用者处理(在这种情况下它被检查),要么应该一直向上到高级处理程序(在这种情况下,如果它不被检查是最简单的)。

所有这些都是受控异常。未检查的异常是RuntimeException的子类。问题不在于如何处理它们,而在于你的代码是否应该抛出它们。如果你不想让编译器告诉你你还没有处理一个异常,那么你可以使用一个未检查的(RuntimeException的子类)异常。这些应该保存在你无法恢复的情况下,比如内存不足等。

某个异常是否为“受控异常”与是否捕获它或在捕获块中做了什么无关。它是异常类的属性。Exception的子类,除了RuntimeException及其子类,都是受控异常。

Java编译器迫使您要么捕获已检查的异常,要么在方法签名中声明它们。它本应提高程序的安全性,但大多数人的意见似乎是,它不值得它带来的设计问题。

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

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

关于未检查异常和已检查异常之间的区别,我最喜欢的描述来自Java教程的试用文章“未检查异常-争议”(很抱歉在这篇文章中介绍了所有基本的内容-但是,嘿,基本的有时是最好的):

这是底线原则:如果客户可以合理地 希望从异常中恢复,使其成为受控异常。如果 客户端不能做任何事情来从异常中恢复 未经检查的异常

“抛出哪种类型的异常”的核心是语义的(在某种程度上),上面的引用提供了一个很好的指导方针(因此,我仍然被c#摆脱受控异常的概念所震撼——特别是Liskov认为它们有用)。

接下来的问题就变得合乎逻辑了:编译器希望我显式地响应哪些异常?你希望客户能从中恢复过来。

已检查-容易发生。在编译时选中。

小薇。FileOperations

未检查-由于不良数据。在运行时签入。

如. .

String s = "abc";
Object o = s;
Integer i = (Integer) o;

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
    at Sample.main(Sample.java:9)

这里的异常是由于错误的数据,在编译时无法确定。