个人博客Faye’s Blog
一、处理异常
1.异常层次
所有异常都由 Throwable
继承而来。
Error
类描述了 Java 运行时系统的内部错误和资源耗尽错误。Exception
层次分为 RuntimeException
和其他异常。
派生于 RuntimeException
的异常包含:
- 错误的类型转换
- 数组访问越界
- 访问
null
指针 - …
不是派生于 RuntimeException
的异常包含:
- 试图在文件末尾后读取文件
- 试图打开一个不存在的文件
- 试图根据给定的字符串查找 Class 对象,而该类不存在
- …
“如果出现了 RuntimeException
异常,那一定是你的问题”
派生于 Error
类和 RuntimeException
类的异常称为非受查异常,其他异常称为受查异常。
2.声明受查异常
方法必须声明所有可能抛出的受查异常,但不用声明从 Error
继承的错误(不可控制),不用声明从 RuntimeException
继承的非受查异常(尽量避免)。
子类覆盖超类的方法,在子类中声明的受查异常不可比超类中的更通用。(若超类方法没有抛出任何受查异常,子类也不能抛出)
3.创建异常类
一般地,定义的类应该包含两个构造器,一个是默认的,另一个是带有详细信息的构造器
class FileFormatException extends Exception{
public FileFormatException(){}
public FileFormatException(String mess){
super(mess);
}
}
4.抛出异常
1.找到或创建合适的异常类
2.创建该异常类的对象
3.抛出该对象
二、捕获异常
1.捕获异常
如果某个异常发生时未在任何地方进行捕获,那么程序就会终止。如果捕获一个异常,必须设置 try/catch
语句块。
通常,应该捕获那些知道如何处理的异常,而将那些不知怎样处理的异常进行传递。如果要传递异常,就必须在方法首部添加 throws
关键字。
存在多个 catch
时,子类错误必须写在前面。
2.finally
子句
不管是否有异常被捕获,finally
子句中的代码都被执行。如果要抛出异常,则先执行 finally
子句,再抛出异常。
建议解耦合
try/catch
和try/finally
语句块:try { try { } finally { } } catch () { }
内层的
try
语句,确保finally
子句的执行。外层的try
语句确保报告错误,且将报告finally
子句中出现的错误。
当利用 return
从 try
中退出时,在返回前,finally
子句的内容将执行。若 finally
子句中也有 return
语句,将会覆盖之前的返回值。
finally
子句抛出异常同上述 return
。会抑制 try
中的异常,应该使用异常变量将其暂存,然后调用 addSuppressed
,添加原始异常,再抛出。
3.再次抛出异常和异常链
包装异常,将原始异常设置为新异常的原因。
catch(SQLException e){
Throwable se = new NewException("new exception");
se.initCause(e);
throw se;
}
Throwable e = se.getCause();
得到原始异常。
4.带资源的 try
语句
try(Resource ...){
...
}
try
块退出时,自动调用 .close()
。若 close
方法抛出异常,该异常就会被自动捕获,并用 addSuppressed
方法增加到原来的异常。可以调用 getSuppressed
方法得到 close
方法抛出的异常。
5.堆栈轨迹
堆栈轨迹(stack trace)是一个方法调用过程的列表。
-
Java 程序终止,未捕获异常时,该列表就会显示。
-
调用
Throwable
类的printStackTrace
方法,访问堆栈轨迹的信息 -
使用
getStackTrace
方法,得到StackTraceElement
对象的数组。
6.使用异常机制技巧
1.异常处理不能代替测试
2.不要过分细化异常
3.利用异常层次结构:
不要只抛出 RuntimeException
异常,不要只捕获 Throwable
异常,否则会使程序更难读。将一个异常转换成另一个更合适的异常时不要犹豫。
4.不要压制异常
若认为异常很重要,就应该处理
5.早抛出,晚捕获
-
检测错误时,苛刻比放任更好。在出错的地方抛出,比在后面抛出其他异常好。
-
不要害怕传递异常
三、断言
断言机制允许在测试阶段向代码中插入一些检查语句,代码发布后,这些插入的检查语句会被自动移走。
assert 条件;
assert 条件:表达式;
会对表达式进行检测,若为 false
,则抛出一个 AssertionError
异常。(表达式会传入 AssertionError
构造器,转换成一个消息字符串)。
四、日志
基本日志:
使用全局日志记录器 Logger.getGlobal().info("test log");
。在适当的地方调用Logger.getGlobal().setLevel(Level.OFF);
,会取消所有日志。
五、调试技巧
1.可以打印或记录任意变量的值
2.可在每个类防止一个单独的 main
方法,可以对每个类进行单元测试。
3.利用 Throwable
类的 printStackTrace
方法。
可从异常对象获得堆栈轨迹。(可以在任何位置插入 Thread.dumpStack();
会的堆栈轨迹,无需异常)