Java异常机制与 finally 与return的关系;

来源:互联网 发布:mac有道词典离线词库 编辑:程序博客网 时间:2024/06/06 12:36

异常机制是指当程序出现错误后,程序如何处理。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。


Java异常体系图:
这里写图片描述

Throwable 类是 Java 语言中所有错误或异常的超类。上图是网上比较常见的一种图,给出了我们常见的几个异常;

  • Error:

Error表示程序在运行期间出现了十分严重、不可恢复的错误,在这种情况下应用程序只能中止运行,例如JAVA 虚拟机出现错误。Error是一种unchecked Exception,编译器不会检查Error是否被处理,在程序中不用捕获Error类型的异常。一般情况下,在程序中也不应该抛出Error类型的异常。

  • Checked Exception异常:

Checked Exception异常(上图中的粉色异常),所有继承自Exception 并且不是RuntimeException 的异常都是checked Exception,上图中的 IOException 和 ClassNotFoundException。JAVA 语言规定必须对checked Exception作处理,编译器会对此作检查,要么在方法体中声明抛出(throws)checked Exception,要么使用catch语句捕获checked Exception进行处理,不然不能通过编译。

  • RuntimeException异常:

RuntimeException 是一种Unchecked Exception,即表示编译器不会检查程序是否对RuntimeException作了处理,在程序中不必捕获RuntimException类型的异常,也不必在方法体声明抛出RuntimeException类。RuntimeException发生的时候,表示程序中出现了编程错误,所以应该找出错误修改程序,而不是去捕获RuntimeException。


异常处理的流程

  • 遇到异常,方法立即结束,同时,抛出一个异常对象,并不会返回一个值;
  • 调用该方法的程序也不会继续执行下去,而是搜索一个可以处理该异常的异常处理器,并执行其中的代码;

几点说明:

1、两种异常都可以捕获

运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误的操作。一旦出现错误,建议让程序终止
受检查异常表示程序可以处理的异常。要么 try 要么 throws,否则调用会出错,连编译也无法通过。当然,这两种异常都是可以通过程序来捕获并处理的,例如:

public static int testNoFinally1(){        int b = 20;        int c=0;        try {            c = b/0;//这里抛出了运行时异常            System.out.println("try block");            return b += 80;         }        catch (Exception e) {            System.out.println("catch block");        }        finally {            System.out.println("finally block");        }        System.out.println("after catch /0");        return c;    }

输出结果:

catch blockfinally blockafter catch /00
2、异常处理的语法规则:
  • try语句不能单独存在,可以和catch,finally组成 try...catch...finallytry...catchtry...finally三种结构,catch语句可以有一个或多个,finally语句最多一个,try、catch、finally这三个关键字均不能单独使用。
  • try、catch、finally 三个代码块中变量的作用域分别独立而不能相互访问。如果要在三个块中都可以访问,则需要将变量定义到这些块的外面。
  • 多个catch块时候,Java虚拟机会匹配其中一个异常类或其子类,就执行这个catch块,而不会再执行别的catch块。
  • throw语句后不允许有紧跟其他语句,因为这些没有机会执行。编译都通不过;
  • 如果一个方法调用了另外一个声明抛出异常的方法,那么这个方法要么处理异常,要么声明抛出。
3、 throw和throws关键字的区别

throw用来抛出一个异常,在方法体内。语法格式为:throw 异常对象。
throws用来声明方法可能会抛出什么异常,在方法名后,语法格式为:throws 异常类型1,异常类型2…异常类型n。

4、子类重写父类的方法时候不能声明抛出比父类大的异常

当我们子类要重写父类中的方法,如果父类的方法有异常声明,那么子类重写这个方法时候,所要声明的异常不应该比父类的大。只能是小等,或者可以没有。



Return 与 Finally
以下两种情况 finally 语句是不会被执行的:

(1)try语句没有被执行到,如在try语句之前就返回了比如在try之前抛出了异常,这样finally语句就不会执行,这也说明了finally语句被执行的必要而非充分条件是:相应的try语句一定被执行到。

(2)在try块中有System.exit(0);这样的语句,System.exit(0);是终止Java虚拟机JVM的,连JVM都停止了,所有都结束了,当然finally语句也不会被执行到。


Finally语句的执行与return的关系:不知道finally语句是在try的return之前执行还是之后执行?
答: finally 语句是在 try 的 return 语句执行之后 (return expression 中 expression表达式执行之后),return返回之前 (return返回expression结果之前)执行。

1. finally语句在return语句执行之后 return返回之前执行的。

public static int testFinalReturn1() {        int b = 20;        try {            System.out.println("try block");            //这个return 可以分两步 第一计算 b+=80; 第二步:返回 结果100;            //在执行完第一步时,回去执行finally里面的东西,然后再执行第二步;            //如果是return 100这样的表达式,可以把第一步看中100=100也会在执行完finally的东西执行返回;            return b += 80;        } catch (Exception e) {            System.out.println("catch block");        } finally {            System.out.println("finally block");            //由于第一步b+=80使得b=100所以这个判断肯定会执行            if (b > 25) {                System.out.println("b>25, b = " + b);                //b=b-30; //不建议代码,我们在finally主要是做释放资源和善后的结果;                //如果我们在这里修改了b的值 不会影响到return的b=100的结果,            }        }        return b;    }

输出结果:

System.out.println(testFinalReturn1());try blockreturn statementfinally blockafter return

2. finally块中的 return 语句会覆盖 try 块中的 return 返回;

public static int testFinalReturn2() {        int b = 20;        try {            System.out.println("try block");            return b += 80;        } catch (Exception e) {            System.out.println("catch block");        } finally {            System.out.println("finally block");            if (b > 25) {                System.out.println("b>25, b = " + b);                b=b-30; //不建议代码,我们在finally主要是做释放资源和善后的结果;            }            return b;//这里的return语句会覆盖上面return语句的第二步所以b=100-30,        }        //return b;    }

输出结果:

System.out.println(testFinalReturn2());try blockfinally blockb>25, b = 10070

注意: 这说明finally里的return直接返回了,就不管try中是否还有返回语句,finally里加上return过后,finally外面的return b就变成不可到达语句了,也就是永远不能被执行到,所以需要注释掉否则编译器报错;


3. 在finally中对return expression中的expression值进行修改是否会影响到return的返回值;

3.1 对于基本类型及其包装类不会修改其原始值
public static int testFinalReturnModify1() {        int b = 20;        try {            System.out.println("try block");            //在此Step1 b=100, Step2 return 100;            return b += 80;        } catch (Exception e) {            System.out.println("catch block");        } finally {            System.out.println("finally block");            if (b > 25) {                System.out.println("b>25, b = " + b);            }            //对b的值进行了修改;不会影响到原来值,            b = 150;        }        //由于上面已在Step2中返回来了这里就不会再执行;        return 2000;    }

输出结果:

System.out.println(testFinalReturnModify1());try blockfinally blockb>25, b = 100100
public static Integer testFinalReturnModify2() {        Integer b = new Integer(20);        Integer c = new Integer(80);        try {            System.out.println("try block");            //在此自动拆箱Step1 b=100, Step2 return 100;            return b += c;        } catch (Exception e) {            System.out.println("catch block");        } finally {            System.out.println("finally block");            if (b > 25) {                System.out.println("b>25, b = " + b);            }            //对b的值进行了修改;不会影响到原来值,            b = 150;        }        //由于上面已在Step2中返回来了这里就不会再执行;        return 2000;    }

输出结果

System.out.println(testFinalReturnModify2());try blockfinally blockb>25, b = 100100
3.2 对于String 类型不会修改其原始值,但是在finally执行完再进行拼接;
public static String testFinalReturnModify4() {        String str = "hello";        try {            System.out.println("try block");            //这个比较特殊,限制性finally  在进行拼接返回;            return str+" world";        } catch (Exception e) {            System.out.println("catch block");        } finally {            System.out.println("finally block");            System.out.println("str = " + str);//hello            if ("hello world".equals(str)) {//false                System.out.println("str = " + str);            }            //对 str 的值进行了修改;不会影响到原来值,            str = "abc";        }        //由于上面已在Step2中返回来了这里就不会再执行;        return "def";    }

输出结果:

System.out.println(testFinalReturnModify4());try blockfinally blockstr = hellohello world
3.3 对于引用 类型会修改其原始值:
public static Map testFinalReturnModifyRef(){        Map<String, String> map = new HashMap<String, String>();        //在此对KEY赋予初始值 INIT;        map.put("KEY", "INIT");        try {            map.put("KEY", "TRY");            return map;        }        catch (Exception e) {            map.put("KEY", "CATCH");        }        finally {            map.put("KEY", "FINALLY");            //将这个引用赋为 null;            map = null;        }        return map;    }

输出结果:

System.out.println(testFinalReturnModifyRef());{KEY=FINALLY}
static class Student{        private String name;        private int age;        public Student(){}        public Student(String name,int age){            this.name = name;            this.age = age;        }        public String getName() {            return name;        }        public void setName(String name) {            this.name = name;        }        public int getAge() {            return age;        }        public void setAge(int age) {            this.age = age;        }        @Override        public String toString() {            return "Student [name=" + name + ", age=" + age + "]";        }    }    public static Student testFinalReturnModifyRef2(){        Student stu = new Student("zhangsan",30);        //在此对KEY赋予初始值 INIT;        try {            return stu;        }        catch (Exception e) {            System.out.println("catch..");            stu.setName("catch");        }        finally {            System.out.println("finally -->"+stu );            System.out.println("finally..");                //编译不通过 意思是说这个stu不可以访问;            stu.setName("finally");        }        return stu;    }

输出结果:

finally -->Student [name=zhangsan, age=30]finally..Student [name=finally, age=30]

4. try块里的return语句在异常的情况下不会被执行,这样具体返回哪个看情况。

public static int test4() {        int b = 20;        try {            System.out.println("try block");            b = b / 0;//抛出运行时异常            //下面这个语句不会再执行,而是直接执行处理完异常以后的语句;            return b += 80;        } catch (Exception e) {            b += 15;            System.out.println("catch block: b+=15 ->" + b);        } finally {            System.out.println("finally block");            if (b > 25) {                System.out.println("b>25, b = " + b);            }            b += 50;        }    //处理完异常以后,从异常处理完结束的地方继续往下执行:        return 204;    }

输出结果:

System.out.println(test4());try blockcatch block: b+=1535finally blockb>25, b = 35204
5. 当发生异常后,catch中的return执行情况与未发生异常时try中return的执行情况完全一样。
public static int test5() {        int b = 20;        try {            System.out.println("try block");            //抛出异常            b = b /0;            //下面这个语句用于执行不了了;            return b += 80;        } catch (Exception e) {            System.out.println("catch block");            //step 1 b=20+15 step2 return 35;            return b += 15;        } finally {            System.out.println("finally block");            if (b > 25) {                System.out.println("b>25, b = " + b);            }            //不会影响到上面的35;            b += 50;        }        //这里执行不到,不需要写 编译不通过;        //return b;    }

输出结果:

System.out.println(test5());try blockcatch blockfinally blockb>25, b = 3535

在此特别鸣谢以下前辈给出的经验和知识的分享;

Java常见的异常小结:
异常的深入研究与分析:
Java异常体系详解:
Java finally语句到底是在return之前还是之后执行 重点感谢

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 3dmax文件打开失败怎么办 夏天吹空调嘴歪怎么办 燃气热水器温度调节拧不动怎么办 能率热水器震动声大怎么办 车底盘磕了漏油怎么办 法士特变速箱的随动阀漏气了怎么办 大灯随动afs失灵怎么办 2017款迈腾大灯随动故障怎么办 微信gps信号不好怎么办 苹果6s定位不准怎么办 电脑不读取u盘怎么办 注塑机上的料烤坨了怎么办 智能锁电机坏了怎么办 注塑机加热嘴内扣突了怎么办 tpu粘在螺杆上怎么办 注塑机锁模时会有射退动作怎么办 电动车刹车油泵不打油怎么办 cad转pdf颜色浅怎么办 松下多功能传真一体机卡纸怎么办 无刷电机坏了怎么办 6kv高压电机绝缘不合格怎么办? 400t油压机下降太慢怎么办 无法连线到服务器1~1怎么办? 数控车床车角度不亮怎么办 超市存包柜的票不见了怎么办 交货期来不及导致船期延误怎么办 跑1000米中途累怎么办 手指被机器压烂怎么办 机械手不能回归原点该怎么办 前缘送纸纸板翘怎么办 三菱AL 1R.2报警怎么办 工作好但领导不好伺候怎么办 孕妇憋尿憋的小腹疼怎么办 怀孕憋尿憋的小腹疼怎么办 半夜憋尿憋的小腹疼怎么办 新生儿大便次数较多怎么办 母猎生下三天没有奶怎么办 孩孑大便干不爱喝水怎么办 发那科1050报警怎么办 plc模块bf亮了怎么办 plc模块df亮了怎么办