基础知识
1、异常是一种Exception类型的对象(异常是一种对象)
因为异常是对象,所以你catch住的也是对象,下面程序代码中catch的参数是Exception类型的ex引用变量
try { } catch(Exception ex) { //Exception类型的对象可以是任何它的子类的实例 //尝试恢复 }
2、如果你的程序代码会抓住异常,那是谁把它抛出来的?
//有风险、会抛出异常的代码
public void takeRisk() throws BadException {//必须声明它会抛出BadException if(abandonAllHope) { throw new BadException();//创建Exception对象并抛出 } } //调用该方法的程序代码 public coid crossFingers() { try { anObject.takeRisk(); } catch(BadException ae) { System.out.println("Aaargh"); ex.printStackTrace();//如果无法从异常中恢复,至少也要使用printStackTrace()来列出有用的信息 } }
举例:
public class Test { int age; public void getAge(int age) throws AgeException{//声明它会抛出AgeException this.age = age; if(age > 100) { throw new AgeException();//创建AgeException对象并抛出 } } public static void main(String[] args) { Test t = new Test(); t.getAge(200);//调用会抛出异常的方法 } } class AgeException extends Exception {//自定义异常AgeException继承Exception // }
异常是程序运行期间出现的,区别于程序编译期间的代码错误
3、为什么编译器不管RuntimeException
大部分RuntimeException都是因为程序逻辑问题,而不是以你所无法预测或防止的方法出现的
执行期间失败状况,你无法保证文件一直都在,你无法保证服务器不会死机,但是你可以确保程序
不会运行不合理的逻辑,例如对只有5项元素的数组取第八个元素的值。
4、try/catch块的控制流程
5、finally:无论如何都要执行的部分
/* 如果try/catch块有return指令,finally还是会执行, 流程会条到finally然后再回到return指令 */ try { turnOvenOn(); x.bake(); trunOvenOff(); } catch (BakingException ex) { ex.printStackTrace(); trunOvenOff(); }
6、try/catch/finally/throw/throws实例:
public class Test { public static void main(String[] args) { String test = "yes"; try { System.out.println("start try"); doRisky(test); System.out.println("end try"); } catch(ScaryExteption ae) { System.out.println("scary exception"); } finally { System.out.println("finally"); } System.out.println("end of main"); } static void doRisky(String test) throws ScaryExteption { System.out.println("start risky"); if("yes".equals(test)) { throw new ScaryExteption(); } System.out.println("end risky");//不再执行 return;//不再执行 } } class ScaryExteption extends Exception {}//ScaryExteption为自定义异常
String test = "yes"执行结果:
String test = "no"执行结果:
7、处理多重异常
多重方法可以抛出多个异常,但该方法的声明必须要含有全部可能的检查异常(若两个或两个异常的异常有共同的父类时,可以只声明该父类就行)
public class Laundry { public void doLaundry() throws PantsException, LingerieException { //可能抛出两个异常的程序代码 } } public class Foo { public void () { Laundry laundry = new Laundry(); try{ laundry.doLaundry(); } catch(PantsException pex) { //恢复程序代码 } catch(LingerieException lex) { //恢复程序代码 } } }
8、异常也是多态的
异常是对象,因此异常也能够以多态的方式来引用
9、可以用父类来处理所有的异常并不代表就应该这么做
把异常处理程序代码写成只有一个catch块以父型的Exception来捕获
try { laundry.doLaundry(); } catch (Exception ex) {//恢复什么?这个会捕获所有的异常,一次你会搞不清楚哪里出错 //解决方案...... }
有多个catch块时要从小到大,不能把大篮子放在小篮子上面(否则会无法通过编译)
个人理解:下面例子中:当我们用父类捕获异常时(多个子类捕获效果一致)实际上在第一个异常抛出的时候就catch住了,而后程序就会执行恢复此问题的方法,程序结束。
我们不能用父类捕获异常是因为程序运行的时候,会根据捕获的不用异常执行不同的恢复该异常的方法,如果我们用父类捕获异常,那么只能写一个
异常的恢复方法,难以满足一个恢复方法恢复所有类型的异常
public class Test { int age; public void getAge(int age) throws Age1Exception, Age2Exception{ this.age = age; if(age > 100) { throw new Age1Exception(); } if (age > 200) {//上面抛出异常后,该if语句也不再运行 throw new Age2Exception(); } } public static void main(String[] args) { Test t = new Test(); try { t.getAge(500); }catch (Age1Exception ae) {//只能catch住Age1Exception ae.printStackTrace(); }catch (Age2Exception ae) {//不运行 ae.printStackTrace(); } } /*效果同上面分别catch public static void main(String[] args) { Test t = new Test(); try { t.getAge(500); }catch (Exception ae) { ae.printStackTrace(); } } */ } class Age1Exception extends Exception {} class Age2Exception extends Exception {}
10、不想处理异常时。可以把它duck掉来避开(交给下一个调用的方法来处理)
(ducking只是在踢皮球,早晚还得有人来处理这件事,如果连main()也duck掉异常,程序可编译但是运行报错)
执行结果: