04 异常处理
异常
异常分为 Exception 和 Error,其继承关系如下
TODO: Insert inheritance image
Exception 是可以被处理的异常,如NullPointerException或IllegalArgumentException;Error 是不一定能被处理的异常,如OutOfMemoryError,NoClassDefFoundError
如果 Exception 没有被处理,那么程序无法被编译。
方法可以通过throw关键词表示调用方法时可能抛出的异常,如String.getBytes(String)的签名
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException {
...
}
在调用String.getBytes(String)时,必须使用一个 try-catch 块处理UnsupportedEncodingException。
不过如果在另一个被标记为throws UnsupportedEncodingException的方法里调用String.getBytes(String),我们就不需要处理异常。异常处理会被下放到调用该方法的其他方法。最坏情况我们必须要在main方法里处理该异常,除非main也被标记为throws UnsupportedEncodingException。如
在处理异常时,我们可以使用printStackTrace()打印异常栈,如
try {
// ...
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
try-catch 语句
多个 catch 语句按顺序分别处理不同异常
使用catch (ExceptionA | ExceptionB)同时处理多个异常
使用 finally 语句,无论异常是否发生,都在最后执行特定逻辑,如清理资源
抛出异常
使用throw关键词抛出异常
自定义异常
在大型项目中,我们会定义一套异常继承体系。
首先自定义一个BaseException,然后继承这一根异常,定义其他异常。
BaseException本身通常继承自RuntimeException。
NullPointerException (NPE)
为避免 NPE,可以
使用空数据,而非
null。例如,返回一个空数组,或空字符串使用
Optional<T>
断言
assert
日志(log)
Java.util.logging
Common Logging
Log4j
SLF4J 和 Logback
杂项
- 如果 catch 和 finally 都抛出了异常,只有 finally 的异常会被处理,catch 的异常会被屏蔽(Suppressed Exception)。不推荐这么做。