约书亚·布洛赫在《有效的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中,什么时候应该创建检查异常,什么时候应该是运行时异常?

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


当前回答

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

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

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

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

其他回答

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

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

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

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

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

上述异常是否被认为是受控异常? 没有 如果异常是RuntimeException,那么您正在处理的异常并不会使其成为Checked exception。 RuntimeException是未检查的异常吗? 是的

受控异常是java.lang.Exception的子类 未检查异常是java.lang.RuntimeException的子类

抛出已检查异常的调用需要包含在try{}块中,或者在方法调用方的更高级别中处理。在这种情况下,当前方法必须声明它抛出上述异常,以便调用者可以做出适当的安排来处理异常。

希望这能有所帮助。

问:我应该把确切的泡沫 异常或屏蔽它使用异常?

A:是的,这是一个非常好的问题,也是重要的设计考虑因素。Exception类是一个非常通用的异常类,可用于包装内部低级异常。您最好创建一个自定义异常,并将其封装在其中。但是,还有一个很大的问题——永远不要模糊潜在的根本原因。对于前任,不要做下面的事情

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException("Cannot login!!"); //<-- Eat away original root cause, thus obscuring underlying problem.
}

你可以这样做:

try {
     attemptLogin(userCredentials);
} catch (SQLException sqle) {
     throw new LoginFailureException(sqle); //<-- Wrap original exception to pass on root cause upstairs!.
}

对生产支持团队来说,消除原始的根本原因,掩盖无法恢复的实际原因是一场噩梦,因为他们只能访问应用程序日志和错误消息。 虽然后者是一种更好的设计,但许多人不经常使用它,因为开发人员无法将底层消息传递给调用者。因此,请明确指出:无论是否封装在任何特定于应用程序的异常中,始终将实际异常传递回去。

在尝试捕获runtimeexception时

runtimeexception作为一般规则不应该被尝试捕获。它们通常是一个编程错误的信号,应该被置之不理。相反,程序员应该在调用一些可能导致RuntimeException的代码之前检查错误条件。为例:

try {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welcome to my site!);
} catch (NullPointerException npe) {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

这是一种糟糕的编程实践。相反,null检查应该像-那样执行

if (userObject != null) {
    setStatusMessage("Hello Mr. " + userObject.getName() + ", Welome to my site!);
} else {
   sendError("Sorry, your userObject was null. Please contact customer care.");
}

但有时这种错误检查是昂贵的,例如数字格式,考虑这个-

try {
    String userAge = (String)request.getParameter("age");
    userObject.setAge(Integer.parseInt(strUserAge));
} catch (NumberFormatException npe) {
   sendError("Sorry, Age is supposed to be an Integer. Please try again.");
}

在这里,预调用错误检查不值得花费精力,因为它本质上意味着复制parseInt()方法中的所有字符串到整数转换代码——如果由开发人员实现,则很容易出错。因此,最好是取消try-catch。

因此NullPointerException和NumberFormatException都是runtimeexception,捕获一个NullPointerException应该替换为一个优雅的空检查,而我建议显式捕获NumberFormatException以避免可能引入容易出错的代码。

Java distinguishes between two categories of exceptions (checked & unchecked). Java enforces a catch or declared requirement for checked exceptions. An exception's type determines whether an exception is checked or unchecked. All exception types that are direct or indirect subclasses of class RuntimeException are unchecked exception. All classes that inherit from class Exception but not RuntimeException are considered to be checked exceptions. Classes that inherit from class Error are considered to be unchecked. Compiler checks each method call and deceleration to determine whether the method throws checked exception. If so the compiler ensures the exception is caught or is declared in a throws clause. To satisfy the declare part of the catch-or-declare requirement, the method that generates the exception must provide a throws clause containing the checked-exception. Exception classes are defined to be checked when they are considered important enough to catch or declare.

运行时异常: 运行时异常被称为未检查的异常。所有其他例外 是受控异常,并且它们不是派生自java.lang.RuntimeException。

检查异常: 必须在代码中的某个地方捕获受控异常。如果您调用 方法,该方法引发已检查异常,但您没有捕获该已检查异常 在某些地方,您的代码将无法编译。这就是为什么他们被称为检查 异常:编译器检查以确保它们被处理或声明。

Java API中的许多方法都会抛出检查过的异常,因此您将经常编写异常处理程序来处理由您没有编写的方法生成的异常。