异常、断言和日志
异常
Throwable类
- Exception和Error都派生于Throwable类
Exception类
- 异常有两个分支:
- RuntimeException运行时异常,一般为程序错误导致:比如:
- 错误的强制类型转换
- 数组访问越界
- 访问null指针
- 其他异常(也称为检查型异常):需要主动处理这类异常。比如
- 文件异常IOException
- Class未找到异常
声明异常
- 在方法首部通过throws抛出所有检查型异常,非检查型异常应该自行处理
- 子类覆盖超类方法时,抛出的检查型异常不能比超类的大
捕获异常
- 多个不存在继承关系的异常可以合并到同一个catch块,用 “|” 分隔
- 多个catch块声明的异常类型,超类不能在子类之前,否则永远进不了子类catch块
- catch块中可以再次抛出异常,通常用于改变异常类型,建议将原始异常设置为新异常的“原因”,这样在捕获到新异常时不会丢失原始异常的细节
- 一个方法中发生了检查型异常,但这个方法不允许抛出检查型异常(比如父类方法没有抛出检查型异常),就可以包装成一个运行时异常,将检查型异常添加到新一场的原因中
finally
- 不论try块有没有抛出异常,或者catch块是否捕获到异常,或者catch块有没有再次抛出异常,finally块的代码都将执行
- 常用于释放资源
- 可以只有try-finally,没有catch块
- finally块中如果有return语句,将会改变流程,覆盖try中的return
try-with-resources语句
try(Resource res=...){
...
}
- 如果资源实现了AutoCloseable接口,在处理资源时可以替代在finally中释放资源的办法,try块结束后会自动关闭资源
- 在原始的 try-finally方式中关闭资源,finally也可能抛出异常,这就很麻烦,try-with-resources方式如果在关闭资源时发生异常,会将close异常自动添加到try块的原始异常中,重新抛出原始异常
- 可以有catch块,也可以有finally块,在关闭资源后执行
日志
基本日志
- 全局日志记录器:Logger.getGlobal()
- 默认记录器日志级别为INFO
- 默认日志处理器时ConsoleHandle,默认日志级别是INFO
高级日志
- 日志级别
- SEVERE
- WARNING
- INFO
- CONFIG
- FINE
- FINER
- FINEST
- 设置日志记录器级别:logger.setLevel(Level)
- 设置日志处理器级别:handle.setLevel(Level),日志处理器级别不能高于日志记录器级别,否则会过滤
修改日志管理器配置
- 配置文件位于jre/lib/logging.properties(Java9之前)
- 可以修改默认日志记录器、日志处理器级别
- 可以自定义配置日志记录器、日志处理器
过滤器
- 除了日志级别的过滤,每个日志记录器和日志处理器都可以配置一个过滤器来完成过滤
- 过滤器要实现Filter接口,再调用setFilter()方法设置
格式化器
- 实现了Formatter接口
- 日志处理器通过setFormatter设置自定义格式化
日志技巧
- 开发中尽量将日志级别设置到INFO以下,线上环境再设置为INFO,就可以过滤掉开发中的一些调试日志
调试技巧
-
创建一个日志代理类,将方法调用信息打印出来
-
打印异常对象的堆栈轨迹 e.printStackTrace
-
在代码中打印当前调用轨迹 Thread.dumpStack()
-
将异常堆栈轨迹转换成字符串:
StringWriter out = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(out));
String description = out.toString();