finally子句的用法

执行流程

finally子句是异常捕获的一部分

try{
}catch(Exception e){
}finally{
}

三部分的执行顺序是try块检测并抛出异常,然后由catch子句捕获,最后执行finally子句。
try块必须有,catch和finally子句不一定全都必须,可以二选一,也可都有。

class TException extends Exception {}
public class FinallyWorks {
    static int count = 0;
    public static void main(String[] args) {
        while (true) {
            try {
                if (count++ == 0) {
                    throw new TException();
                }
                System.out.println("No exception");
            } catch (Exception e) {
                System.out.println("TException");
            } finally {
                System.out.println("In finally clause");
                if (count == 2) break;
            }
        }
    }
}
//output:
TException
In finally clause
No exception
In finally clause

finally子句的作用是不论try和catch中的代码执行情况如何,它都会执行,断言的终止也会执行。(有一种情况特殊就是在try或者catch中执行System.exit(1);,它会直接终止程序,从而让finally得不到执行

try块中有return,finally子句还会执行吗?

答案是会,那么它在什么时候执行呢?看完你就知道了,下面详细讨论各种情况:

public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(new Test().backInt());
    }
    int backInt() {
        int i = 1;
        try {
        	System.out.println("execute1");
            return i;
        } finally {
            i = 2;
            System.out.println("execute2");
        }
    }
}
//output
execute1
execute2
1

可以看出try块中即使存在return语句,finally子句还是执行了。但是输出的结果却是1,这是为什么?我们调试下看看
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
但是最后输出却是1,那不是finally中的操作没有效果了吗?

一切从编译文件入手,原来是这样啊!!!

好,现在看看它的编译文件,一切都知道了。

public class Test {
    public Test() {
    }
    public static void main(String[] args) throws Exception {
        System.out.println((new Test()).backInt());
    }
    int backInt() {
        byte i = 1;
        byte var2;
        try {
            System.out.println("execute1");
            var2 = i;
        } finally {
            int i = true;
            System.out.println("execute2");
        }
        return var2;
    }
}

如果是对象呢,看下面这段代码:

public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(new Test().backObject());
    }
    static Object object = new Object();
    Object backObject() {
        try {
            System.out.println(object);
            return object;
        } finally {
            object = new Object();
            System.out.println(object);
        }
    }
}
//output:
java.lang.Object@33d4f6b4
java.lang.Object@6290be01
java.lang.Object@33d4f6b4

反编译文件:

public class Test {
    static Object object = new Object();
    public Test() {
    }
    public static void main(String[] args) throws Exception {
        System.out.println((new Test()).backObject());
    }
    Object backObject() {
        Object var1;
        try {
            System.out.println(object);
            var1 = object;
        } finally {
            object = new Object();
            System.out.println(object);
        }
        return var1;
    }
}

看来都是一样的。
如果我改变返回对象其中的某个属性,最终能成功返回吗?答案是会的,看下面代码:

public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(new Test().backObject());
    }
    static A object = new A();
    A backObject() {
        try {
            System.out.println(object);
            return object;
        } finally {
            object.i = 2;
            System.out.println(object);
        }
    }
}
class A {
    public int i = 1;
    @Override
    public String toString() {
        return "" + i;
    }
}
//output:
1
2
2

反编译文件:

public class Test {
    static A object = new A();
    public Test() {
    }
    public static void main(String[] args) throws Exception {
        System.out.println((new Test()).backObject());
    }
    A backObject() {
        A var1;
        try {
            System.out.println(object);
            var1 = object;
        } finally {
            object.i = 2;
            System.out.println(object);
        }
        return var1;
    }
}

如果try块和finally子句都存在return语句

public class Test {
    public static void main(String[] args) throws Exception {
        System.out.println(new Test().backObject());
    }
    static A object = new A();
    A backObject() {
        try {
            System.out.println(object);
            return object;
        } finally {
            object = new A();
            System.out.println(object);
            return object;
        }
    }
}
class A {
    public int i = 1;
    @Override
    public String toString() {
        return super.toString();
    }
}
//output:
com.security.bcsx.A@71c2812
com.security.bcsx.A@498ab963
com.security.bcsx.A@498ab963

反编译文件:

public class Test {
    static A object = new A();
    public Test() {
    }
    public static void main(String[] args) throws Exception {
        System.out.println((new Test()).backObject());
    }
    A backObject() {
        try {
            System.out.println(object);
            A var1 = object;
        } finally {
            object = new A();
            System.out.println(object);
            return object;
        }
    }
}

看来最后返回的是finally子句返回的结果。其实这可能是种缺陷,举个例子说,如果在try块中抛出一个异常,可能希望在finally子句中释放锁定的资源,然而finally中又抛出了一个异常,那么最后方法的调用抛出的异常只会是finally子句的异常,try中的异常被屏蔽了,也许就找不到问题发生的地方了。

总结

如果只在try块中return,那么会先保存return的值,再执行finally,最后返回return保存的值。
如果都有return,那么try中的被屏蔽,只执行finally中的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值