1. 在上一讲内容中我们讲了异常的两种处理方式,其中用try + catch + finally结构的处理方式中,可以多个catch,每一个catch块捕获着一种特定类型的异常。如下程序所示:
自定义两个异常如下:
package com.ahuier.exception; public class MyException extends Exception{ /* * 参考ArithmeticException的实现 * 使用supe关键字可以保证将字符串的信息一层一层网上传到Throwable类让其维护字符串描述信息 */ public MyException(){ super(); } public MyException(String message){ super(message); } }
写一个测试异常类:package com.ahuier.exception; public class MyException2 extends Exception { public MyException2(){ super(); } public MyException2(String message){ super(message); } }
编译执行package com.ahuier.exception; public class ExceptionTest4 { public void method(String str) throws MyException, MyException2{ if(str == null){ throw new MyException("传入的字符串参数不能为null"); } else if(str.equals("hello")){ throw new MyException2("传入的字符不能为hello"); } else{ System.out.println(str); } } /* * 根据多态,也可以抛出 Exception类型的异常: * 1) throws Exception * 2) 捕获也可以这样写 catch(Exception e) */ public static void main(String[] args) throws MyException{ try{ ExceptionTest4 test = new ExceptionTest4(); test.method("hello"); }catch(MyException e){ System.out.println("进入到MyException catch块"); e.printStackTrace(); }catch(MyException2 e){ System.out.println("进入到MyException catch块2"); e.printStackTrace(); } //这部有可能会抛出两种异常,有可能抛出的都必须用catch捕获 finally{ System.out.println("异常处理完毕"); } System.out.println("程序执行完毕"); } }
com.ahuier.exception.MyException2: 传入的字符不能为hello
at com.ahuier.exception.ExceptionTest4.method(ExceptionTest4.java:9)
at com.ahuier.exception.ExceptionTest4.main(ExceptionTest4.java:25)
进入到MyException catch块2
异常处理完毕
程序执行完毕【说明】:这边 test.method("hello");传入的是“hello”,则进入MyException2的catch块,如果是test.method(null);传入的是null,则进入MyException的catch块。通过这个程序可以知道,一个程序有多种抛出异常的可能,都要去捕获这些异常,每一个catch捕获一种异常类型。
分析以上程序ExceptionTest4:
else if(str.equals("hello"))
这种写法是不好的,因为如果不做这个判断的话,一旦str为空,则肯定出现空指针异常了。
所以要修改成 else if("hello".equals(str)) 这样把字符串常量写在前面,这种写法的好处是即便str为空的话,也不会抛出异常,而是直接判断为假了。建议以后把常量写在前面,把变量写在后面。
2. 针对上面的程序,我们再讲一个知识点
可以根据多态,可以将几种异常写成一个他们的父类异常Excption,因为这个异常涵盖了他们
【说明】: 我们可以使用多个catch块来捕获异常,这时需要将父类型的catch块放到子类型的catch块之后,这样才能保证后续的catch可能被执行,否则子类型的catch将永远无法到达,Java编译器会报编译错误;如果多个catch块的异常类型是独立的(MyException, MyException2), 那么谁前谁后都是可以的。package com.ahuier.exception; public class ExceptionTest4 { public void method(String str) throws Exception{ if(str == null){ throw new MyException("传入的字符串参数不能为null"); } else if("hello".equals(str)){ throw new MyException2("传入的字符不能为hello"); } else{ System.out.println(str); } } /* * 根据多态,也可以抛出 Exception类型的异常: * 1) throws Exception * 2) 捕获也可以这样写 catch(Exception e) */ public static void main(String[] args) throws MyException{ try{ ExceptionTest4 test = new ExceptionTest4(); test.method("hello"); }catch(MyException e){ System.out.println("进入到MyException catch块"); e.printStackTrace(); }catch(MyException2 e){ System.out.println("进入到MyException2 catch块"); e.printStackTrace(); } //这部有可能会抛出两种异常,有可能抛出的都必须用catch捕获 catch(Exception e){ System.out.println("进入到Exception catch块"); } finally{ System.out.println("异常处理完毕"); } System.out.println("程序执行完毕"); } }
3. 如果try块中存在return语句,那么首先也需要将finally块中的代码执行完毕,然后方法再返回。
编译执行结果:package com.ahuier.exception; public class ExceptionTest5 { public void method(){ try{ System.out.println("进入到catch块"); return; }catch(Exception e){ System.out.println("异常发生了"); }finally{ System.out.println("进入到finally块"); } System.out.println("异常处理后续代码"); } public static void main(String[] args) { ExceptionTest5 test = new ExceptionTest5(); test.method(); } }
进入到catch块
进入到finally块
4. 如果try块中存在System.exit(0)语句,那么就不会执行finally块中的代码,因为System.exit(0)会终止当前运行的Java虚拟机,程序会在虚拟机终止前结束执行。
编译执行结果:package com.ahuier.exception; public class ExceptionTest5 { public void method(){ try{ System.out.println("进入到catch块"); System.exit(0); //如果里面传的参数是0 则正常退出Java虚拟机,程序是在虚拟机上运行的,虚拟机停止,则程序退出不执行了 }catch(Exception e){ System.out.println("异常发生了"); }finally{ System.out.println("进入到finally块"); } System.out.println("异常处理后续代码"); } public static void main(String[] args) { ExceptionTest5 test = new ExceptionTest5(); test.method(); } }
进入到catch块
5. 到此为止我们异常全部讲解完毕,在异常中关键的部分是自定义异常,自定义异常是项目中一个重要的组成部分,需要定义自己一个完善的异常体系。
同时也要学习对异常的处理。
异常的处理有三种方式:
1. 捕获异常
2. 抛出异常
3. 捕获到异常加入自己的信息再抛出,供调用这个方法的那个方法来处理这一个异常。