Java异常处理机制类图如下:
Thorwable类是所有异常和错误的超类,有两个子类Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常,又分别称之为不受检查异常(Unchecked Exception)和强制检查异常(Checked Exception)。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类,是Checked Exception。从程序语法角度讲是必须进行处 理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常。
下面的示例检查除数是否为负数,如果是则抛出异常。
强制检查异常类:
/** * 强制检查的异常 * @author lenovo * */ class MinusException extends Exception{ private static final long serialVersionUID = 1L; private long minus; /** * 强制检查的异常 * @param minus */ public MinusException(long minus){ this.minus = minus; } @Override public String getMessage() { return minus + "为负数,不合法!"; } }不受检查异常类:
/** * 不受检查的异常 * @author lenovo * */ class MinusRunTimeException extends RuntimeException{ private static final long serialVersionUID = 1L; private long minus; /** * 不受检查的异常 * @param minus */ public MinusRunTimeException(long minus){ this.minus = minus; } @Override public String getMessage() { return minus + "为负数,不合法!"; } }运算类:
class Minus{ public double throwException(long a, long b) throws MinusException { if (b < 0) { throw new MinusException(b); } return a/b; } public double throwRunTimeException(long a, long b) { if (b < 0) { throw new MinusRunTimeException(b); } return a/b; } }从运算类我们看到: 如果方法内抛出了强制检查的异常,则必须在方法签名中声明抛出的异常(当然也可以用try捕获机制处理),如此,当这个方法被调用时必须进行异常处理;如果方法内抛出了不受检查的异常,则无需在方法签名中声明异常,如此,当这个方法被调用时,可以选择处理异常,也可以选择不处理异常。
测试:
public class Test { public static void main(String[] args){ Minus minus = new Minus(); //强制检查异常 try{ System.out.println(minus.throwException(2, -1)); } catch (MinusException e) { e.printStackTrace(); } //不处理不受检查异常 System.out.println(minus.throwRunTimeException(2, -2)); System.out.println("Main end!"); } }输出:
cn.com.exception.MinusException: -1为负数,不合法! at cn.com.exception.Minus.throwException(Test.java:25) at cn.com.exception.Test.main(Test.java:9) Exception in thread "main" cn.com.exception.MinusRunTimeException: -2为负数,不合法! at cn.com.exception.Minus.throwRunTimeException(Test.java:32) at cn.com.exception.Test.main(Test.java:14)最后一条输出语句没有执行,而倒数第二条语句执行了。
修改测试类,选择捕获不受检查的异常:
public class Test { public static void main(String[] args){ Minus minus = new Minus(); //强制检查异常 try{ System.out.println(minus.throwException(2, -1)); } catch (MinusException e) { e.printStackTrace(); } //处理不受检查异常 try{ System.out.println(minus.throwRunTimeException(2, -2)); } catch (MinusRunTimeException e) { e.printStackTrace(); } System.out.println("Main end!"); } }输出:
cn.com.exception.MinusException: -1为负数,不合法! at cn.com.exception.Minus.throwException(Test.java:30) at cn.com.exception.Test.main(Test.java:9) cn.com.exception.MinusRunTimeException: -2为负数,不合法! at cn.com.exception.Minus.throwRunTimeException(Test.java:37) at cn.com.exception.Test.main(Test.java:15) Main end!
最后一条语句执行了!这说明:当程序抛出异常时,如果我们没有捕获异常,程序不会执行下面的代码(而是跳到外层的catch语句之后开始执行);如果我们捕获了异常,当程序执行完catch里的代码(异常处理程序)后,会继续执行下面的代码,也就是说,如果我们捕获了异常,可以让程序在指定的地方从异常状态恢复到正常状态。
最后说明:所有抛出的异常(要么由虚拟机抛出,要么由程序员抛出)都会被捕捉和处理,要么被程序员捕捉和处理,要么被虚拟机捕捉和处理。
从抛出异常到处理异常(catch语句)之间的代码是不会被执行的。例如,看下面的代码:
//处理不受检查异常 try{ System.out.println(minus.throwRunTimeException(2, -2)); } catch (MinusRunTimeException e) { e.printStackTrace(); }插入一句代码:
//处理不受检查异常 try{ System.out.println(minus.throwRunTimeException(2, -2)); System.out.println("hello"); } catch (MinusRunTimeException e) { e.printStackTrace(); }程序并不会输出hello。