基本概念
Exception 和 Error 都是继承了 Throwable,java 中只有 Throwable 的实例是可以被抛出、捕获的。
Exception 是程序正常运行中,可以预料的意外情况,可以被捕获,进行相应处理。
Error 是是正常情况下,不大可能出现的情况,会导致程序处于非正常、不可恢复状态,因为其是非正常的,所以不便于或者不需要捕获,常见的 Error 例如 OutOfMemoryError。
Exception 分为 可检查异常、不检查异常。
可检查异常在代码中必须显示的进行捕获处理,这是编译期检查的一部分。
不检查异常时运行时异常,例如 NullPointerException、ArrayIndexOutOfBoundsException,这类异常应该尽量在编码时避免。
image异常处理的常见问题
下面的代码有什么问题?
try{
// ...
Thread.sleep(1000L);
}catch(Exception e){
// 忽略
}
问题1:尽量不要捕获通用异常,应该捕获特定异常
这里 Thread.sleep()
抛出的是 InterruptedException
,而捕获的是通用异常 Exception
。
我们在日常工作中,读代码的机会很多,软件工程是协作的艺术,我们必须让自己的代码直观的表达出尽可能多的信息,Exception
显然不适合,而且 Exception
也会使本应扩散出来的异常(例如 RuntimeException)被捕获了。
问题2:不要生吞异常
上面的 catch 中直接把异常忽略了,这就是生吞异常。
生吞异常往往是感觉这个异常产生的概率很小,忽略了也无所谓,但程序需要严谨,不能做这种假设。
和生吞异常类似的做法是 e.printStackTrace()
,只是简单的把异常信息输出到了标准错误流,应输出到日志系统中,以便后续查找问题。
Throw early 原则
public void readPreferences(String fileName){
//...perform operations...
InputStream in = new FileInputStream(fileName);
//...read the preferences file...
}
如果 fileName 是 null,就会抛出 NullPointerException,应该今早的抛出问题:
public void readPreferences(String fileName){
Objects.requireNonNull(fileName);
//...perform operations...
InputStream in = new FileInputStream(fileName);
//...read the preferences file...
}