Java中的异常分为两大类:
1.Checked Exception(非Runtime Exception)
2.Unchecked Exception(Runtime Exception)
运行时异常:RuntimeException类是Exception类的子类,它叫做运行时异常,Java中的所有运行时异常都会直接或者间接地继承自RuntimeException类,运行时异常,是在编译的时候检测不到,只有在运行时候才会出现,这些异常是可以通过程序员的谨慎避免的,比如说空指针异常,数组下标越界等。
非运行时异常:Java中凡是继承自Exception,而不继承自RuntimeException类的异常都是非运行时异常。这是我们编程人员无法避免和控制的异常,比如说创建读取文件的流,会出现文件不存在异常。
异常处理的一般结构
- try {
- // 可能会发生异常的程序代码
- } catch (Type1 id1) {
- // 捕获并处理try抛出的异常类型Type1
- } catch (Type2 id2) {
- // 捕获并处理try抛出的异常类型Type2
- } finally {
- // 无论是否发生异常,都将执行的语句块
- }
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
总结:
1)try 块:用于捕获异常。其后可接零个或多个catch块,零个或者一个finally块。如果没有catch块,则必须跟一个finally块;
2)当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块或者根本没有catch块的时候(没有catch块,必须有一个finally块。如果函数声明时,注明throws 异常,这个异常将由调用者处理,否则,此异常将会抛给JVM处理。无论如何,finally语句块里的语句还是会被执行,但finally语句块后的任何语句不会被执行,也就是finally语句块后的代码都是不可达的;
3)在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,出现异常之后的语句也不会被执行。程序将跳到catch语句块,并按照顺序查询catch块的Exception类型,找到后进入catch执行语句,其他的catch语句块将不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;
4)使用throws关键字将异常抛给调用者后,如果调用者不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的调用者。
5)在 try-catch-finally 结构中,可重新抛出异常。
重申:
1)由于运行异常是我们在编写代码的时候无法预料的,所以一般不会有异常处理try catch块,这中情况下,出现异常,整个程序就死掉了,死在出现异常的语句,之后的程序都不会运行。
2)当一个块中(try块,catch块,finally块),执行某个语句出现异常,则,这个块中,异常语句下的语句都不会执行。
3)try中的异常,由catch块接受和处理。catch 和finally 块中出现的异常,可以接着嵌套try,catch,也可以在函数声明时候throws 向上抛出异常,由调用者处理。如果这些都没有,此异常将会抛给JVM处理。
这有个看起来好长好长的代码,其实一点也不多,做做看,对了,就说明异常玩的溜啦~
- public class TestException {
- public TestException() {
- }
- 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) {
- TestException testException1 = new TestException();
- try {
- testException1.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
这道题,折腾我好久,终于懂得,为什么2在catch中throw e ,然而 1 却没有进行catch啦,而是正常的运行try块,引用我群里头的一位哥哥的回答,大家一看就懂啦!
调用方法的时候,会有一个方法栈帧, 先执行testEx2 的 catch里面的throw e, 相当于把e压入到这个栈中,但是方法并没有退出,接着执行finally,finally是一定会执行的你肯定知道吧,finally里面return ret,相当于把ret又压到栈顶。这时候方法结束,弹出栈顶元素return false 作为结果。所以你throw出来的e相当于被覆盖了。 之前有个很经典的问题就是 return 和 finally 哪个先执行,其实是 return 后面的表达式会先被执行,把结果压入栈中,然后执行finally中的表达式,最后方法结束,弹出栈顶元素。
ok 异常搞明白了!!
自定义java异常
public Myexception extends Exception{
public Myexception (String errorMessage ){
super (errorMessage);
}
}
如果父类抛出多个异常,则覆盖方法必须抛出异常的子集,不能抛出新异常.