java的基本理念,结构不佳的代码不能运行。
异常,java中错误报告机制。
[1] 异常一旦发生,就不允许程序按照原来的路径继续执行下去,而是转到异常处理程序。
[2] 异常参数,默认构造器和传参数的构造器。Throwable是异常类型的根类,异常的错误信息会根据异常名称相应提示。
[3] 捕获异常 try{
} catch(){
}catch(){ }//可能try块中会有多种异常,要一一捕获
[4] java支持终止和恢复两种模型的异常处理,恢复太难实现,一般是终止模型处理,错误已经无法挽回了。
[5] 可以自定义异常类,但必须从java中的异常类继承而来。构造器可以不带参数,也可以有一个默认构造参数。
[6] printStackTrace()方法,打印从方法调用处到异常抛出处的方法调用序列。
[7] java.util.logging工具将异常信息记录到日志中。
[8] 异常是对象,在继承中也可以添加其他的成员变量或函数,但是通常不会关心这些。
[9] 异常说明:要么处理异常,要么在异常说明中表明该方法将产生异常。
12.6 捕获所有异常
[1] 可以写一个异常处理程序捕获所有异常
catch(Exception e){
//处理
}
[2] Exception中主要方法 getMessage() 、 printStackTrace() 、fillInStackTrace()用于程序重新抛出异常和错误时。
[3] printStackTrace() 栈轨迹,方法的调用序列,第0个元素,即栈顶是调用序列中最后一个方法调用。
[4] 重新抛出异常,printStackTrace()显示的还是原来异常的调用栈信息,要用fillInStackTrace()
catch(Exception e){
//处理
throw (Exception)e. fillInStackTrace();//新异常发生地
}
[5] 异常都是通过new在堆上创建对象,所以垃圾回收器会自动把它们清理掉。
[6] 异常链,捕获一个异常之后抛出另一个异常,希望把原始异常的信息保存下来。Throwable子类构造器中,接收一个cause(表示原始异常),将原始异常传递给新异常。带有cause参数的构造器很少,如果要把其他类型的异常链接起来,应该使用initCause()方法而不是构造器。
SomeException e = new SomeException(); e.initCause(new PreviousException);
12.7 java标准异常
[1] 根类Throwable,分为两类:Error(编译时和系统错误)和Exception(可以被抛出的基本类型,通常程序员关心的问题)。
[2] 特例:RuntimeException,有很多继承自它的子类。它们会自动被java虚拟机抛出,不必在异常说明中列出来。如果没有捕获,RuntimeException类型的异常会穿越所有的路径直接到达main()方法,而不会被捕获;程序退出前调用printStackException。
[3] RuntimeException 代表的是编程错误:一类是无法预料的错误(如用户输入),另一类是程序员应该在代码中检查的错误(如数组下表越界)。
12.8 finally进行清理
try{
}catch(Exception e){// 这里可以有0个或多个catch
}finally{ // 一定会被执行}
[1] java异常不允许回到异常抛出点,可以讲try块放在循环中,直到达到某个条件再结束循环。
[2] finally主要用途:把除内存(垃圾回收器来做)之外的其他资源回复到他们的初始状态。如关闭打开的文件,网络连接等。
[3] 涉及break,continue等子句时,finally也会执行。
[4] try块中return了,finally仍可以运行。
[5] finally子句可能造成某种情况下的异常丢失。如finally中加return等。
12.9 异常限制
[1] 当覆盖方法时,只能抛出在基类方法的异常说明中列出的那些异常。异常限制对构造器不起作用,可以添加任意的异常抛出。但派生类构造器的异常说明中必须包含基类构造器的异常说明。
[2] 基类抛出时,导出类的方法也可以不抛出异常。或者抛出基类异常类的子类。
12.10 构造器
对于在构造阶段可能会抛出异常,并要求清理的类,最安全的方式是使用嵌套的try子句。
惯用原则:在创建要清理的对象之后,立即进入一个try-finally语句块。
try {
InputFile in = new InputFile("Cleanup.java");
try {
// Perform line-by-line processing here...
} catch(Exception e) {
e.printStackTrace(System.out);
} finally {
in.dispose();
}
} catch(Exception e){
System.out.println("InputFile construction failed");
}
12.11 异常匹配
抛出异常时,异常处理系统会按照代码书写顺序找“最近”的处理程序。
派生类的对象也可以匹配其基类的处理程序。基类的处理程序会屏蔽派生类的异常,编译器会报错。
try {
throw new Sneeze();
} catch(Sneeze s) { //Annoyance是Sneeze的基类。 如果把两个catch的顺序互换会报错。
// ...
} catch(Annoyance a) {
// ...
}
12.12 其他可选方式
“checked Exception”使问题变得复杂,会强制你在可能还没准备好处理错误的时候被迫加上catch子句。带来的好处比麻烦多。
两种解决办法:用RuntimeException来包装“checked Exception”,RE是在运行时才抛出的异常。另一种方法,创建自己的RuntimeException子类。
try {
//处理
}catch(Exception e) {
// Adapt to unchecked: 转换
throw new RuntimeException(e);
}
12.13 异常使用指南
在以下情况使用:结束程序时,为了简化程序,让类库和程序更安全。
总结:异常的精髓在于报告错误,恢复能力非常有限(10%)的样子。