重温try-catch-finally

2021-04-16  本文已影响0人  艺超51iwowo

本周一个重要的收获是自己在代码中,引入了java7的try-with-resource方法。该方法实际上用的比较少,和同事讨论的时候,有一个问题比较有趣,如果同时使用try-with-resource和finally,那资源是在finally之前关闭的,还是之后呢?

try-with-resource下finally代码块的执行顺序

示例代码如下:

注意: 使用try-with-resource的类,必须实现AutoCloseable接口。

public class TryWithResourceTest {

    public static void main(String[] args) {
        try (MyTest myTest = new MyTest()) {
            System.out.println("main");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }
    }

    private static class MyTest implements  AutoCloseable {

        @Override
        public void close() throws Exception {
            System.out.println("myTest.close");
        }
    }
}

执行结果如下:

image-20210321065844425

可以看到,close方法是在正常的finally之前执行的,也就是之前大家广知的finally代码块是最后执行的。

finally代码块的一些其他注意事项

1. finally代码块一定会执行吗?

执行方法后,直接exit,此时finally模块无法正常执行。

image-20210321070516185
2. finally代码块中如果对return中的变量做了修改,那返回结果会修改吗?

2.1 先看引用类型,在MyTest类中增加String 类型的text和Integer类型的number字段,示例代码如下

 private static MyTest executeReference() {
        MyTest myTest = new MyTest();
        try {
            myTest.setText("try-return");
            myTest.setNumber(10);
            return myTest;
        } finally {
            myTest.setText("finally-return");
            myTest.setNumber(20);
        }
    }

在finally模块中,对返回值做了修改,输出结果如下

image-20210321071707539

此时,finally模块会修改try中返回的值。

2.2 但是测试发现,如果变为基本类型或者包装类型,情况又不一样

测试代码:

private static Integer executeBox() {
        Integer integer = new Integer(300);
        try {
            return integer;
        } finally {
            integer = new Integer(400);
        }
    }

    private static int executeUnBox() {
        int integer = 300;
        try {
            return integer;
        } finally {
            integer = 400;
        }
    }
image-20210321071852239

此时的返回结果,是以try中的返回结果为准。

2.3 最后再来看一下基本类型数组的情况

private static int[] executeArray() {
        int[] test = new int[] {0, 1};
        try {
            return test;
        } finally {
            test[1] = 10;
        }
    }

此时的测试结果,对应位置的数据已经被finally模块修改过了。

image-20210321072353664

所以,

  1. 如果是引用类型,finally可以对其中的值进行修改。
  2. 如果是基本类型和其包装类型,finally不会进行修改,以try语句中的为准
3. finally代码块中如果也有return语句,那会返回什么结果呢?

针对上述情况中,基本类型和包装类型的测试代码中,直接在finally模块中,执行return语句。

 private static Integer executeBox() {
        Integer integer = new Integer(300);
        try {
            return integer;
        } finally {
            integer = new Integer(400);
            return integer;
        }
    }

    private static int executeUnBox() {
        int integer = 300;
        try {
            return integer;
        } finally {
            integer = 400;
            return integer;
        }
    }

此时的测试结果会是finally中最后修改的值

image-20210321072900945

但是实际情况下,此时如果有安装Alibaba代码规约检查工具,会有对应的提示,这种情况容易触发问题,需引起重视。

image-20210321072954699
上一篇下一篇

猜你喜欢

热点阅读