Java异常处理
Java异常处理
错误处理
错误
在计算机程序执行的过程中,错误总会出现:
l 用户输入错误
l 读写文件错误
l 网络错误,内存耗尽,无法连接打印机
如果方法调用出错,调用方如何得知这个错误:
l 约定返回错误码
异常
java使用异常来表示错误:
l 异常是class,本身带有类型信息
l 异常可以在任何地方抛出
l 异常只需要在上层捕获,和方法调离
java的异常体系
java的异常本身就是class
l Throwable
n Error
n Exception
u RuntimeException
u IOException
必须捕获的异常:
包括Exception及其子类,但不包括RuntimeException及其子类,称为Checked Exception
不需要捕获的异常:
l error及其子类
l RuntimeException及其子类
为什么java要定义这样异常体系?
error是发生了严重错误,程序对此一般无能为力
Exception是发生了运行时逻辑错误,应该捕获异常并处理
捕获异常
l 使用try…catch捕获异常
l 可能发生异常的语句放在try{}中
l 使用catch捕获对应的exception及其子类
可以使用多个catch子句:
l 每个catch捕获对应的Exception及其子类
l 从上到下匹配,匹配到某个catch后不再继续匹配
l 子类必须写在前面
finally
finally语句块保证有无错误都会执行
finally不是必须的
finally总是最后处理
multi-catch
如果某些异常的处理逻辑相同:
不存在继承关系,必须编写多条catch语句
可以使用|表示多种Exception
必须jdk>=1.7以上
申明异常
对可能抛出Checked Exception的方法调用
l 捕获Exception并处理
l 不捕获但通过throws声明
l 通过thorws声明仍需在上层捕获
l main()是最后捕获Exception的机会
抛出异常
异常的传播
当某个方法抛出异常时:
l 如果当前方法没有捕获,异常就被抛到上层调用方法
l 直到遇到某个try…catch被捕获
l printStackTrace()可以打印出方法的调用栈
抛出异常
如何抛出异常:
l 创建某个exception的实例
l 用throw语句抛出
转换异常
如果一个方法捕获了某个异常后,又在catch子句中抛出新的异常,就相当于把抛出异常类型转换了 :
新的异常丢失了原始的异常信息,所以要把原始的异常的实例e传进新的异常
抛出异常
如果在catch子句中又抛出一个异常,那么在抛出异常之前:
l finally语句会保证执行
l 如果我们在finally语句中又抛出异常,那么原先catch的异常不再抛出
l 没有被抛出的异常称为被屏蔽的异常(suppressed exception)
java异常传播只能传播一个异常,后面抛出会把前面抛出且没有被catch覆盖
Suppressed
如何保存所有的异常信息?
l 用origin变量保存原始异常
l 如果存在原始异常,用addSuppressed()添加新的异常
l 如果存在原始异常,或新异常,最后在finally抛出
l 用getSuppressed()获取所有suppressed exception
l jdk>=1.7
自定义异常
自定义异常应该从合适的exception派生
推荐RuntimeExcrption
自定义异常应该提供多个构造方法
断言和日志
Assertion
断言是一种程序调试方式
l 使用assert关键字
l 断言条件预期为 true
l 如果断言失败,抛出AssertionError
l 可选断言消息
assert x >= 0 : “x must >= 0”;
特点
l 断言失败时会抛出AssertionError,导致程序结束退出
l 不能用于可恢复的程序错误
l 只应该用于开发和测试阶段
什么是可恢复的错误:如果我们认为一个程序错误是可以恢复,例如:一个变量是否为空
对于可恢复的程序错误:
l 不应该使用断言
l 应该抛出异常在上层捕获
启用断言
jvm默认关闭断言指令
给java虚拟机传递-ea参数启用断言
可以指定特定的类启用断言: -ea:完整包名+类名
可以指定特定的包启用断言: -ea:完整包名…(注意最后加三个点)
断言很少被使用,更好的方法编写单元测试。
java日志
Logging
为了取代System.out.println()
可以设置输出样式
可以设置输出级别,禁止某些级别输出
可以被重定向到文件
可以按包名控制日志级别
JDK Logging
定义了7个日志级别:
SEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
局限
l jvm启动时读取配置文件并完成初始化
l jvm启动后无法修改配置
l 需要在jvm启动时传递参数
-Djava.util.logging.config.file = config-file-name
Commons Logging
是apache创建的日志模块
l 可以连接不同的日志系统
l 可以通过配置文件指定挂接的日志系统
l 自动搜索并使用Log4j
l 如果找不到Log4j,使用jdk Logging(jdk>=1.4)
定义了6个日志级别:
FATAL
ERROR
WARINNG
INFO
DEBUG
TRACE
使用Log4j
Log4j目前最流行的日志框架
l 1.x Log4j
l 2.x Log4j2
因为commons Logging 优先使用Log4j
建议始终使用commons Logging接口来写入日志
开发阶段无需引入Log4j
使用Log4j需要把正确的配置文件和相关的jar包放入classpath
使用配置文件可灵活修改日志,无修改代码