1. java异常机制概述
1.1 继承体系
Error: 表示错误,一般指JVM相关的不可修复的错误,如:系统崩溃,内存溢出,JVM错误等。由JVM抛出,我们不需要进行处理
Exception: 表示异常,指程序中出现不正常的情况,该问题可以修复处理。
RuntimeException: 运行时异常。在编译时期,可以不处理(抛出或捕获处理),编译会通过。但在运行时期可以会产生的异常。常见的如:NullPointerException, ArithmeticException等
CheckedException: 编译时异常。在编译时期会进行检查,如果没有进行处理(抛出或捕获处理),编译不会通过。常见的如:IOException, SQLException等
public class ExceptionTest { public void testNullPointerException() { throw new NullPointerException();//编译通过 } public void testCheckedException() { try { throw new IOException();//必须进行处理,否则编译不通过 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
1.2 自定义异常
class MyException extends Exception{} class MyRuntimeException extends RuntimeException{} public class ExceptionTest { public void testMyException() { try { throw new MyException(); } catch (MyException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void testMyRuntimeException() { throw new MyRuntimeException(); } }
当我们自定义的异常MyException直接继承父类Exception时,也类似于受查异常,必须在编译期进行处理,否则编译不通过。当我们自定义的异常MyRuntimeException直接继承父类RuntimeException时,跟RuntimeException一样,不需要在编译器处理也可以编译通过。
2. 异常处理机制
2.1 try-catch
2.1.1 语法结构
try {
//可能发生异常的代码(监控区域)
} catch (ExceptionType1 e1) {
//当监控区域产生ExceptionType1 类型或其子类的异常时,执行的代码块
} catch (ExceptionType2 e2) {
//当监控区域产生ExceptionType2 类型或其子类的异常时,执行的代码块
} ...
2.2.2 异常匹配原则
如果抛出的异常对象属于catch异常的类型或其子类时,则认为生成的异常对象与其异常类型匹配;
当抛出的异常类型同时与多个catch异常类型匹配时,应该按照代码顺序执行,且一旦被一块catch捕获后,就不能被其他catch捕获了。
public class ExceptionTest { public static void main(String[] args) { try { int a = 1/0; } catch (ArithmeticException e) { System.out.println("被ArithmeticException捕获..."); } catch (Exception e) { System.out.println("被Exception捕获..."); } System.out.println("end..."); } }
结果:
被ArithmeticException捕获... end...
注意:1.我们一般将子类的Exception放在前面,否则该处代码将永远不会被执行(这种现象叫做异常屏蔽)
2.一旦try代码块中未抛出异常,或抛出异常后被捕获处理且未再抛出异常,则,try-catch代码块后的代码将会继续执行
2.2 try-catch-finally
2.2.1 语法结构
try {
//可能发生异常的代码(监控区域)
} catch (ExceptionType1 e1) {
//当监控区域产生ExceptionType1 类型或其子类的异常时,执行的代码块
} catch (ExceptionType2 e2) {
//当监控区域产生ExceptionType2 类型或其子类的异常时,执行的代码块
}
......
finally {
//最终执行的代码块
}
2.2.2 finally代码块:
2.2.2.1 无论是否捕获处理了异常,finally代码块一般都会执行
2.2.2.2 如果try或catch代码块中有return语句,则finally代码块会在return语句执行前执行
2.2.2.3 在几类特殊情况下,finally语句不会被执行:
在finally语句中发生异常,在语句执行过程中退出了jvm(如:调用System.exit(0)),程序所在的线程死亡等
2.2.2.4 在方法中如果有返回值和没有返回值,程序调用结果会不同,看下面的实例:
public class MyExceptionTest { @Test public void test() { try { int a = testThrowOrReturn(); System.out.println(a); } catch (Exception e) { // TODO Auto-generated catch block System.out.println(e.getMessage()); } } private int testThrowOrReturn() throws Exception { // TODO Auto-generated method stub try { System.out.println("try代码块"); int a = 1/0; return a; } catch (Exception e) { System.out.println("catch代码块"); throw new Exception("catch中异常"); } finally { System.out.println("finally代码块"); return -1; } } }
执行结果:
try代码块 catch代码块 finally代码块 -1
try语句中1/0时抛出异常,被catch语句捕获,打印了catch代码块。之后就执行了finally代码块,返回-1。即catch语句中throw
new Exception代码并没有执行。如果执行了会被test方法捕获并打印出来。我们从结果看出,并没有打印e.getMessage().
再看下面这个例子:
public class MyExceptionTest { @Test public void test() { try { testThrow(); } catch (Exception e) { // TODO Auto-generated catch block System.out.println(e.getMessage()); } } private void testThrow() throws Exception{ try { System.out.println("try代码块"); int a = 1/0; } catch (Exception e) { System.out.println("catch代码块"); throw new Exception("catch中异常"); } finally { System.out.println("finally代码块"); } } }
运行结果:
try代码块 catch代码块 finally代码块 catch中异常
catch代码块中的异常有被抛出。在finally代码块执行完成之后(没有返回值),又将atch代码块中的异常抛出。
3. 抛出异常
3.1 throw
3.1.1 运用于方法内部,表示抛出一个异常对象,并结束执行当前代码块
3.2 throws
3.2.1 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理该异常(当然方法调用者也可以选择不处理,但必须继续抛出,如果选择抛出,则最终将交给jvm)
4. 最后网上留了一道例题(例题)
package com.tca.thinkInJava.chap12.test; public class ExceptionDemo { public ExceptionDemo() { } boolean testEx() throws Exception { boolean ret = true; try { ret = testEx1(); } catch (Exception e) { System.out.println("testEx, catch exception"); ret = false; throw e; } finally { System.out.println("testEx, finally; return value=" + ret); return ret; } } boolean testEx1() throws Exception { boolean ret = true; try { ret = testEx2(); if (!ret) { return false; } System.out.println("testEx1, at the end of try"); return ret; } catch (Exception e) { System.out.println("testEx1, catch exception"); ret = false; throw e; } finally { System.out.println("testEx1, finally; return value=" + ret); return ret; } } boolean testEx2() throws Exception { boolean ret = true; try { int b = 12; int c; for (int i = 2; i >= -2; i--) { c = b / i; System.out.println("i=" + i); } return true; } catch (Exception e) { System.out.println("testEx2, catch exception"); ret = false; throw e; } finally { System.out.println("testEx2, finally; return value=" + ret); return ret; } } public static void main(String[] args) { ExceptionDemo testException = new ExceptionDemo(); try { testException.testEx(); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
i=2 i=1 testEx2, catch exception testEx2, finally; return value=false testEx1, finally; return value=false testEx, finally; return value=false