课程咨询 :186 8716 1620      qq:2066486918

昆明Java培训 > 达内新闻 > 【昆明Java培训】不要在finally块中处理返回值
  • 【昆明Java培训】不要在finally块中处理返回值

    发布:昆明Java培训      来源:达内新闻      时间:2016-10-19

  • 昆明Java培训的老师知道,在finally代码块中处理返回值,这是考试和面试中经常出现的题目。虽然可以以此来出考试题,但在项目中绝对不能再finally代码块中出现return语句,这是因为这种处理方式非常容易产生"误解",会误导开 发者。例如如下代码:

    public class Client113 {

    public static void main(String[] args) {

    try {

    System.out.println(doStuff(-1));

    System.out.println(doStuff(100));

    } catch (Exception e) {

    System.out.println("这里是永远不会到达的");

    }

    }

    //该方法抛出受检异常

    public static int doStuff(int _p) throws Exception {

    try {

    if (_p < 0) {

    throw new DataFormatException("数据格式错误");

    } else {

    return _p;

    }

    } catch (Exception e) {

    //异常处理

    throw e;

    } finally {

    return -1;

    }

    }

    }

    对于这段代码,有两个问题:main方法中的doStuff方法的返回值是什么?doStuff方法永远都不会抛出异常吗?

    昆明Java培训的老师的答案是:doStuff(-1)的值是-1,doStuff(100)的值也是-1,调用doStuff方法永远都不会抛出异常,有这么神奇?原因就是我们在finally代码块中加入了return语句,而这会导致出现以下两个问题:

    (1)、覆盖了try代码块中的return返回值

    当执行doStuff(-1)时,doStuff方法产生了DataFormatException异常,catch块在捕捉此异常后直接抛出,之后代码执行到finally代码块,就会重置返回值,结果就是-1了。也就是出现先返回,再重置返回的情况。

    有人可能会思考,是不是可以定义变量,在finally中修改后return呢?代码如下:

    public static int doStuff() {

    int a = 1;

    try {

    return a;

    } catch (Exception e) {

    } finally {

    //重新修改一下返回值

    a = -1;

    }

    return 0;

    }

    该方法的返回值永远是1,不会是-1或0(为什么不会执行到" return 0 "呢?原因是finally执行完毕后该方法已经有返回值了,后续代码就不会再执行了),这都是源于异常代码块的处理方式,在代码中try代码块就标志着运行时会有一个Throwale线程监视着该方法的运行,若出现异常,则交由异常 辑处理。

    昆明Java培训的老师知道方法是在栈内存中运行的,并且会按照“先进后出”的原则执行,main方法调用了doStuff方法,则main方法在下层,doStuff方法在上层,当doStuff方法执行完" return a "时,此方法的返回值已经确定int类型1(a变量的值,注意基本类型都是拷贝值,而不是引用),此时finally代码块再修改a的值已经与doStuff返回者没有任何关系了,因此该方法永远都会返回1.

    继续追问,那是不是可以在finally代码块中修改引用类型的属性以达到修改返回值的效果呢?代码如下:

    class Person {

    private String name;

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    }

    public static Person doStuffw() {

    Person person = new Person();

    person.setName("张三");

    try {

    return person;

    } catch (Exception e) {   

    } finally {

    //重新修改一下值

    person.setName("李四");

    }

    person.setName("王五");

    return person;

    }

    此方法的返回值永远都是name为李四的Person对象,原因是Person是一个引用对象,在try代码块中的返回值是Person对象的地址,finally中再修改那当然会是李四了。

    (2)、屏蔽异常

    为什么明明把异常throw出去了,但main方法却捕捉不到呢?这是因为异常线程在监视到有异常发生时,就会登记当前的异常类型为DataFormatException,但是当执行器执行finally代码块时,则会重新为doStuff方法赋值,也就是告诉调用者" 方法执行正确,没有产生异常,返回值为1 ",于是乎,异常神奇的消失了,其简化代码如下所示:

    public static void doSomeThing(){

    try{

    //正常抛出异常

    throw new RuntimeException();

    }finally{

    //告诉JVM:该方法正常返回

    return;

    }

    }

    public static void main(String[] args) {

    try {

    doSomeThing();

    } catch (RuntimeException e) {

    System.out.println("这里是永远不会到达的");

    }

    }

    上面finally代码块中的return已经告诉JVM:doSomething方法正常执行结束,没有异常,所以main方法就不可能获得任何异常信息了。这样的代码会使可读性大大降低,读者很难理解作者的意图,增加了修改的难度。

    在finally中处理return返回值,代码看上去很完美,都符合逻辑,但是执行起来就会产生逻辑错误,最重要的一点是finally是用来做异常的收尾处理的,一旦加上了return语句就会让程序的复杂度徒然上升,而且会产生一些隐蔽性非常 高的错误。

    与return语句相似,System.exit(0)或RunTime.getRunTime().exit(0)出现在异常代码块中也会产生非常多的错误假象,增加代码的复杂性,大家有兴趣可以自行研究一下。

    推荐文章

上一篇:java中受检异常尽可能转化为非受检异常

下一篇:spring事务与消息队列

最新开班日期  |  更多

Java--零基础全日制班

Java--零基础全日制班

开班日期:11/30

Java--零基础业余班

Java--零基础业余班

开班日期:11/30

Java--周末提升班

Java--周末提升班

开班日期:11/30

Java--零基础周末班

Java--零基础周末班

开班日期:11/30

  • 网址:http://km .java.tedu.cn      地址:昆明市官渡区春城路62号证券大厦附楼6楼
  • 课程培训电话:186 8716 1620      qq:2066486918    全国服务监督电话:400-827-0010
  • 服务邮箱 ts@tedu.cn
  • 2001-2016 达内国际公司(TARENA INTERNATIONAL,INC.) 版权所有 京ICP证08000853号-56