Java异常处理
讨论如何在Java中处理各种异常情况
Java内置了一套异常处理机制,总是用异常来表示错误。异常是一种class
,因此它本身带有类型信息。
Throwable
有两个体系,Error
和Exception
,Error
表示严重的错误,程序无能为力。OutOfMemoryError
内存耗尽NoClassDefFoundError
被定义StackOverflowError
栈溢出
而Exception是可以被捕获处理的
- 某些异常是应用处理的一部分:如
- 数值类型的格式错误
NumberFormatException
- 未找到文件
FileNotFoundException
- 网络访问失败
SocketException
- 数值类型的格式错误
- 程序编写逻辑不对
- 对Null的对象调用方法或字段
NullPointerException
- 数组索引越界
IndexOutOfBoundsException
- 对Null的对象调用方法或字段
- 某些异常是应用处理的一部分:如
Exception分为两类
RuntimeException
以及它的子类- 非
RuntimeException
必须捕获的异常非
RuntimeException
及其子类
1 | try{ |
- 懒得写try…catch..可以直接在main函数
public static void main(String[] args) throws Exception
捕获异常
多catch语句,只有一个catch被执行,且子类异常必须在父类异常前面,否则不会被子类异常捕获到。
1 | try{ |
- 使用
finally
语句确保有无错误都会执行
抛出异常
1 | void process2(String s){ |
- 抛出异常
1.创建异常 ``2用throw抛出
- 上述抛出异常简写
throw new NullPointerException()
- 先执行finally然后在抛出catch中的异常
- 优先finally抛出异常,调用栈中存在catch中的异常
- 通过
Throwable.getSuppressed()
可以获取所有的Suppressed Exception
自定义异常
常用异常
在需要自定义异常时,保持合理的异常继承体系很重要。
常见做法是自定义一个BaseException作为根异常,然后派生出各种业务类型的异常。
1 | //BaseException |
使用断言Assert
- 断言是一种调试方式,断言失败会抛出AssertionError,只能在开发和测试阶段启用断言;
- 语句
assert x >= 0;
即为断言,断言条件x >= 0
预期为true
。如果计算结果为false
,则断言失败,抛出AssertionError
。 - 使用断言需要JVM启用断言,传递
-enableassertions
(可简写为-ea
)参数 - 对可恢复的错误不能使用断言,而应该抛出异常;
- 断言很少被使用,更好的方法是编写单元测试。
使用JDK Longging替代print检查
Java内置了java.util.logging
,可以直接使用
1 | Logging定义了7个日志级别,从严重到普通: |
需要JVM启动时传递参数-Djava.util.logging.config.file=<config-file-name>
使用第三方库
Commons Logging
可以挂接不同的日志系统,默认自动搜索使用Log4j,如果没有Log4j,再使用JDK Logging
使用方法:
- 通过LogFactory获取Log类的实例
- 使用Log实例的方法打印
- 需要下载导入
1 | Log log = LogFactory.getLog(Main.class); |
log4j
SLF4J和Logback
拼字符串是一个非常麻烦的事情,所以SLF4J的日志接口改进成这样了:一个带占位符的字符串,用后面的变量自动替换占位符。
使用方法和Commons Logging一样