典型问答
Q:请对比 Exception 和 Error,另外,运行时异常与一般异常有什么区别?
A:
Exception 和 Error 都继承 Throwable 类,该类是Java异常处理机制的基本组成类型,只有Throwable类型的示例才可以被抛出(throw)或捕获(catch)。
Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类。
Error 是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如 OutOfMemoryError 之类,都是 Error 的子类。
Exception 是程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
Exception 又分为可检查(checked)异常和不检查(unchecked)异常,可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。
不检查异常就是所谓的运行时异常(RuntimeException),类似 NullPointerException、ArrayIndexOutOfBoundsException 之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。
考点分析
- 理解 Throwable、Exception、Error 的设计和分类。
【必须】掌握那些应用最为广泛的子类,以及如何自定义异常等。
- 理解 Java 语言中操作 Throwable 的元素和实践。
【必须】掌握最基本的语法是,如 try-catch-finally 块,throw、throws 关键字等以及典型场景的处理。
意义 | 位置 | |
---|---|---|
throw | 将产生的异常抛出(强调动作),抛出的既可以是异常引用,也可以是异常对象 | 方法体内 |
throws | 如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。用它修饰的方法向调用者表明该方法可能会抛出异常(可以是一种类型,也可以是多种类型,用逗号隔开) | 方法名或方法名列表之后,方法体前 |
异常处理代码比较繁琐,比如我们需要写很多千篇一律的捕获代码,或者在 finally 里面做一些资源回收工作。随着 Java 语言的发展,JDK7以后引入了一些更加便利的特性,比如 try-with-resources(语法) 和 multiple catch(语法),具体可以参考下面的代码段。在编译时期,会自动生成相应的处理逻辑,比如,自动按照约定俗成 close 那些扩展了 AutoCloseable 或者 Closeable 的对象。
try (BufferedReader br = new BufferedReader(…);
BufferedWriter writer = new BufferedWriter(…)) {// Try-with-resources
// do something
catch ( IOException | XEception e) {// Multiple catch
// Handle it
}
知识扩展
异常处理原则
- 尽量不要捕获类似 Exception 这样的通用异常,而是应该捕获特定异常。
- 不要生吞(swallow:假设这段代码可能不会发生异常,或者感觉忽略异常也无所谓)异常
必须抛出异常或输出到日志。 - “throw early,catch late”原则。
eg:“throw early”——NPE(NullPointerException) ```java public void readPreferences(String fileName){ //…perform operations… InputStream in = new FileInputStream(fileName); //…read the preferences file… }
如果fileName是null,程序就会抛出NullPointerException,但由于没有第一时间暴露问题,堆栈信息可能令人费解,往往需要相对复杂的定位。修改后,让问题“throw early”,对应的异常信息就非常直观。
```java
public void readPreferences(String filename) {
/**
* 检查指定的对象引用不是null,该方法主要用于在方法和构造函数中进行参数验证
*
* @param obj the object reference to check for nullity
* @param <T> the type of the reference
* @return {@code obj} if not {@code null}
* @throws NullPointerException if {@code obj} is {@code null}
*/
Objects. requireNonNull(filename);
//...perform other operations...
InputStream in = new FileInputStream(filename);
//...read the preferences file...
}
“catch late”处理原则:如果不知道如何处理,保留原有cause信息,直接抛出或构建新的异常抛出。在更高层面,有了清晰的(业务)逻辑,往往会更清楚合适的处理方式。