读《java编程思想》12-通过异常处理错误

1、什么是异常
(1)异常情形(exception condition)是指阻止当前方法或作用域继续执行的问题。普通问题只是在当前环境中能够得到足够的信息,总能处理这个错误。而对于异常情形,就不能继续下去了。因为当前环境下无法获得必要的信息来解决问题,能做的是从当前环境中跳出,并且把问题提交给上一级环境。这就是抛出异常时发出的事情。
如:调用库存接口,返回报文中公共参数code为0是正常,1代表库存不足,这是业务问题,走补货流程(普通问题)。但如果什么都不返回,或者超时就是异常。
 
(2)发生异常时
a)将会使用new在堆上创建异常对象 (new)
b)当前执行路径被终止,并从当前环境中弹出对异常对象的引用。(throw)
c)由异常处理程序接管,他的任务是从错误状态中恢复,以使程序继续执行或者换一种方式运行。 (catch)
 
2、 java异常一览
 
(1)Throwable 是所有异常类的父类。
(2)Error是严重的错误,如:虚拟机错误(内存不足,方法调用出栈)和 链接错误(找不到类)。仅靠程序本身无法恢复和预防,java编译器不会检查他们(属于UncheckedException),程序中也不应该捕获他们(try catch),遇到此类错误,建议让程序停止。
(3)Exception表示程序可以处理的异常,可以捕获且可能恢复。遇到此类异常,应该尽量处理,而不应该随意终止异常。Exception 又分为运行时异常(Runtime Exception) 和 被检查异常(Checked Exception)
a)RuntimeException:java编译器不会检查它,又被称为 Unchecked Exception。如:数组下标越界、空指针异常等,如果出现RuntimeException,代表的是编程错误。
b)被检查异常:这类异常如果没有捕获(try catch)或者抛出(throw),编译器会报错。 这类异常一般是由外部引起,如:文件找不到,Sql错误等。
 
3、自定义异常
自定义异常可以继承Exception,作为Checked Exception,受到编译器检查。也可以继承RuntimeException,作为Unchecked Exception。不影响现有代码,运行时透明传递。但最上层一定要有异常处理程序统一处理。否则就是程序错误。
 
4、异常说明
异常说明属于方法声明的一部分,使用throws,标识所有可能会抛出的异常。
void f() throws Exception1, Exception2....
调用有异常说明的方法编译时会被编译器检查,必须捕获(try catch),无论实际抛出没有(throw)。
 
5、栈轨迹
在异常处理程序(catch)中,调用printStackTrace可以打出栈轨迹。
如:
java.lang.RuntimeException: custom
at chapter12.Test55.f1(Test55.java:9)
at chapter12.Test55.f2(Test55.java:13)
at chapter12.Test55.f3(Test55.java:17)
at chapter12.Test55.main(Test55.java:22)
 
第一行异常名称RuntimeException, 构造参数是custom
第二行开始是栈轨迹
 
也可以通过getStackTrance获取栈轨迹数组,栈顶元素为最后一个方法的调用(异常抛出的位置),栈底元素为第一个方法的调用。
 
由此可以看出栈轨迹其实可以称为 ”调用方法“的栈轨迹。
 
 
6、异常链
捕获异常后,当前环境无法处理(恢复),需要再次抛出时,有三种情况:
(1)可以直接抛出已捕获的异常 ,栈轨迹不变。(相当于这里没有捕获)
(2)抛出e.fillTraceException或者一个新的异常(不带cause),栈轨迹被吞掉当前方法以下的调用信息。
如:f2中捕获并如此处理,则f3 和 main 会被吞掉。
(3)想要捕获异常后抛出另外一个异常,并且把原始异常的信息保存下来。这就是为异常链。
我们使用带Throwable类型cause(原因)构造参数抛出异常,这个原因将被当做原始异常。链接起来。
 
如:
按照方法调用的顺序入栈:main->f3->f2->f1
输出为
chapter12.CustomException3: chapter12.CustomException2: chapter12.CustomException1: custom
at chapter12.Test55.f3(Test55.java:24)
at chapter12.Test55.main(Test55.java:30)
Caused by: chapter12.CustomException2: chapter12.CustomException1: custom
at chapter12.Test55.f2(Test55.java:16)
at chapter12.Test55.f3(Test55.java:22)
... 1 more
Caused by: chapter12.CustomException1: custom
at chapter12.Test55.f1(Test55.java:9)
at chapter12.Test55.f2(Test55.java:14)
... 2 more
 
可以看出
(1)异常链上所有异常按照抛出的顺序逆序显示(和栈轨迹相反),最后一个抛出的为主异常,其他为原因。
(2)冒号后面是前一个异常原因msg的拼接。(如此保证第一个可以看到所有原因的msg)
 
由此可以看出异常链,可以称为 ”抛出异常“的链路。
 
7、异常日志输出
(1)printStackTrace() 同时使用System.out输出时,输出顺序会混乱。
那是因为printStackTrace() 默认为printStackTrace(System.err)
因此可以使用printStackTrace(System.out),就可以和System.out顺序输出了。
 
(2)如果需要将异常信息变为字符串文本获取
StringWriter trace = new StringWriter();
e.printStackTrace(new PrintWriter(trace));
System.out.println(trace.toString());
 
8、finally
(1)在return前finally 一定会执行。
(2)在finally中return,会使异常丢失。
 
9、异常的限制
(1)在覆盖方法是,子类只能抛出基类异常说明里已有的异常,或者不抛出。
(2)子类构造器可以抛出任何异常,但是必须包含基类异常说明里已有的异常。
(3)不能基于异常重载方法。
(4)子类没有向上转型,调用方法时,可以不捕获和接口的异常,反之必须捕获。
 
10、异常匹配
抛出异常时,异常处理系统会按照代码的书写书序找到”最近“的处理程序进行处理,不会再继续查找。
因此同时有父子类型异常时,应该先”小“后”大“。
同理可以使用Exception 捕获所有异常,应该放到处理程序列表的末尾。

猜你喜欢

转载自www.cnblogs.com/shineup/p/11453077.html