return之后finally还会执行吗 jdk8_try catch +return经典面试题目+总结

try catch finally 的面试题总是出现在面试题中,此题可以考察初级程序员的基本知识,也可以考察高级程序员的对字节码的理解。下面列举几种情况:

正常的 try catch finally,为什么一定会走finally 呢?

public class Demo {    public static  void  demo(){        try {            tryMehtod();        }catch (Exception e){            handlerException();        }finally {            handleFinally();        }    }    public static void tryMehtod(){    }    public static void handlerException(){    }    public static void handleFinally(){    }}

使用 javap -v Demo 可以生成字节码。

ee40ce40d98ff6f60214bcbaa7b7b48a.png

从上面可以看到,字节码包含了三分finally语句块,都在程序正常return和异常throw之前,其中两处在 try 和 catch 调用 return 之前,一处是在异常 throw 之前。

Java 采用方式是复制 finally 代码块的内容,分别放在 try catch 代码块所有正常 return 和 异常 throw 之前。

相当于如下的代码:

    public   void  demo(){        try {            tryMehtod();            handleFinally();        }catch (Exception e){            handlerException();            handleFinally();        }catch (Throwable e){            handleFinally();            throw  e;        }    }

catch中有return,finally 会执行吗?

  public  static int   calu() {        try {           throw new Exception();        }catch (Exception e){           return 0;        }finally {            System.out.println("finally");        }    }

此时一定会执行的:

b06178f12366c42e568e804044675dca.png

我们看下生成的字节码:

  public static int calu();    descriptor: ()I    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=2, locals=3, args_size=0         0: new           #2                  // class java/lang/Exception         3: dup         4: invokespecial #3                  // Method java/lang/Exception."":()V         7: athrow         8: astore_0         9: iconst_0        10: istore_1        11: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;        14: ldc           #5                  // String finally 执行finally         16: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V        19: iload_1        20: ireturn        21: astore_2        22: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;        25: ldc           #5                  // String finally 执行finally         27: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V        30: aload_2        31: athrow

从上面的字节码看,才catch 里 return 之前,已经执行了finally。

catch中有return,finally也有return,怎么执行?

public class Demo {    public  static int   calu() {        try {           throw new Exception();        }catch (Exception e){           return 2;        }finally {            return 3;        }    }    public static void main( String[] args ) {        System.out.println(calu());    }}

执行结果:

ce8538a33e87d5defb0ab48bb2dafd48.png

我们分析一下字节码:

 public static int calu();    descriptor: ()I    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=2, locals=3, args_size=0         0: new   # 创建一个Exception对象,并将其引用值压入栈顶         3: dup  #复制栈顶数值并将复制值压入栈顶         4: invokespecial #3                  // Method java/lang/Exception."":()V         7: athrow   #将栈顶的异常抛出         8: astore_0  #将栈顶 引用 型数值存入第一个局部变量         9: iconst_2  #将 int 型 2 推送至栈顶        10: istore_1  #将栈顶 int 型数值存入第二个局部变量        11: iconst_3  #将 int 型 3 推送至栈顶        12: ireturn   #从当前方法返回 int        13: astore_2  #将栈顶 引用 型数值存入第三个局部变量        14: iconst_3  #将 int 型 3 推送至栈顶        15: ireturn    #从当前方法返回 int

从上面的字节码看,在第一个return之前 ,取出的数是3,所以返回的是3;

catch中return变量,finally对变量做计算,返回结果是啥?

  public  static int   calu() {        int i = 0;        try {           throw new Exception();        }catch (Exception e){           return i;        }finally {           ++i;        }    }

结果:

5f691184c658e20b79c2a1dd929a4371.png

为什么是0,我们还是从字节码的执行来看:

  public static int calu();    descriptor: ()I    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=2, locals=4, args_size=0         0: iconst_0 #将 int 型 0 推送至栈顶         1: istore_0 #将栈顶 int 型数值存入第一个局部变量         2: new           #2                  // class java/lang/Exception         5: dup         6: invokespecial #3                  // Method java/lang/Exception."":()V         9: athrow #将栈顶的异常抛出        10: astore_1 #将栈顶 引用 型数值存入第二个局部变量        11: iload_0  #将第一个 int 型局部变量推送至栈顶        12: istore_2 #将栈顶 int 型数值存入第三个局部变量        13: iinc          0, 1 #(M 为非负整数,N 为整数)将局部变量数组的第 M 个单元中的 int 值增加 N,常用于 for 循环中自增量的更新        16: iload_2  #将第三个 int 型局部变量推送至栈顶        17: ireturn   #将栈顶的值return        18: astore_3        19: iinc          0, 1        22: aload_3        23: athrow

从上面字节来看ireturn是栈顶的值,此时栈顶的值还是0;需要看12行和16行。

总结

第一,JVM 采用异常表的方式来处理 try-catch 的跳转逻辑;第二,finally 的实现采用拷贝 finally 语句块的方式来实现 finally 一定会执行的语义逻辑;第三,讲解了面试喜欢考的在 finally 中有 return 语句或者 抛异常的情况。第四:当catche和finally都有return,return是finally中的值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值