finally与return之间的关系

焦大
• 阅读 3884

定论

问:finally语句一定会执行吗?
答:

  1. 如果没有执行相应的try语句则不会执行。

  2. 在try语句中如果调用System.exit(0)方法则不会执行。

问:finally会在什么时候执行?
答:如果在try/catch语句中调用转移指令例如:return,break,continue,throw等。则会在转移指令前执行。

总结

finally与return之间的关系

如果在finally中含有return语句,那么try/catch语句的return还有作用吗?

先看一段代码:

/**
 * Created by gavin on 15-9-2.
 */
public class FinallyTest {
    public static void main(String[] args){
        System.out.println(test1());    //3
        System.out.println(test2());    //3
        System.out.println(test3());    //2
        System.out.println(test4());    //2
    }
    public static int test1()
    {
        int i = 1;
        try {
            i = 2;
            return i;
        }finally {
            i++;
            return i;
        }
    }
    public static int test2()
    {
        int i = 1;
        try {
            i = 2;
            return i;
        }finally {
            i = 3;
            return i;
        }
    }
    public static int test3()
    {
        int i = 1;
        try {
            i = 2;
            return i;
        }finally {
            i++;
        }
    }
    public static int test4()
    {
        int i = 1;
        try {
            i = 2;
            return i;
        }finally {
            i = 3;
        }
    }
}

如果你对java内存布局不是很清楚,请看这篇文章:java虚拟机类加载机制和字节码执行引擎

重点关注运行时栈帧结构(局部变量表槽操作数栈)。

上边的代码非常简单,来看一下字节码指令吧

public static int test1();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=0
         0: iconst_1        //定义一个常量1入栈到操作数栈            
         //栈1  0:  1:
         1: istore_0        //出栈,存储到局部便量表槽0         
         //栈   0:1 1:
         2: iconst_2        //定义一个常量2入栈到操作数栈            
         //栈2  0:1 1:
         3: istore_0        //出栈,存储到局部变量表槽0         
         //栈   0:2 1:
         4: iload_0        //从局部便量表槽0入栈到操作数栈   
         //栈2  0:2 1:
         5: istore_1        //出栈,存储到局部变量表槽1         
         //栈   0:2 1:2
         6: iinc          0, 1 //局部变量表槽0变量加1               
         //栈   0:3 1:2
         9: iload_0        //从局部变量表槽0入栈到操作数栈   
         //栈3  0:3 1:2
        10: ireturn         //结束,返回                                 
        //栈3   0:3 1:2
        11: astore_2      
        12: iinc          0, 1
        15: iload_0       
        16: ireturn       
   
  public static int test2();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=0
         0: iconst_1        //定义一个常量1入栈到操作数栈    
         //栈1  0:  1:
         1: istore_0        //出栈,存储到局部便量表槽0 
         //栈   0:1 1:
         2: iconst_2        //定义一个常量2入栈到操作数栈    
         //栈2  0:1 1:
         3: istore_0        //出栈,存储到局部变量表槽0 
         //栈   0:2 1:
         4: iload_0        //从局部变量表槽0入栈                
         //栈2  0:2 1:
         5: istore_1        //出栈,存储到局部变量表槽1 
         //栈   0:2 1:2
         6: iconst_3        //定义一个常量3入栈                 
         //栈3  0:2 1:2
         7: istore_0        //出栈,存储到局部便量表槽0 
         //栈   0:3 1:2
         8: iload_0        //从局部变量表槽0入栈                
         //栈3  0:3 1:2
         9: ireturn        //结束,返回                         
         //栈3  0:3 1:2
        10: astore_2         
        11: iconst_3      
        12: istore_0      
        13: iload_0       
        14: ireturn       
    
  public static int test3();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=0
         0: iconst_1        //定义一个常量1入栈到操作数栈    
         //栈1  0:  1:
         1: istore_0        //出栈,存储到局部便量表槽0 
         //栈   0:1 1:
         2: iconst_2        //定义一个常量2入栈到操作数栈    
         //栈2  0:1 1:
         3: istore_0        //出栈,存储到局部变量表槽0 
         //栈   0:2 1:
         4: iload_0        //从局部变量表槽0入栈                
         //栈2  0:2 1:
         5: istore_1        //出栈,存储到局部变量表槽1 
         //栈   0:2 1:2
         6: iinc          0, 1 //局部变量表槽0变量加一       
         //栈   0:3 1:2
         9: iload_1        //从局部变量表槽1入栈                
         //栈2  0:3 1:2
        10: ireturn         //结束,返回                         
        //栈2   0:3 1:2
        11: astore_2      
        12: iinc          0, 1
        15: aload_2       
        16: athrow        
   
  public static int test4();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=1, locals=3, args_size=0
         0: iconst_1        //定义一个常量1入栈到操作数栈    
         //栈1  0:  1:
         1: istore_0        //出栈,存储到局部便量表槽0 
         //栈   0:1 1:
         2: iconst_2        //定义一个常量2入栈到操作数栈    
         //栈2  0:1 1:
         3: istore_0        //出栈,存储到局部变量表槽0 
         //栈   0:2 1:
         4: iload_0        //从局部变量表槽0入栈                
         //栈2  0:2 1:
         5: istore_1        //出栈,存储到局部变量表槽1 
         //栈   0:2 1:2
         6: iconst_3        //定义一个常量3入栈到操作数栈    
         //栈3  0:2 1:2
         7: istore_0        //出栈,存储到局部变量表槽0 
         //栈   0:3 1:2
         8: iload_1        //从局部变量表槽1入栈                
         //栈2  0:3 1:2
         9: ireturn        //结束,返回                         
         //栈2  0:3 1:2
        10: astore_2      
        11: iconst_3      
        12: istore_0      
        13: aload_2       
        14: athrow

我们看到:

在finally中没有return时,栈中最后存储的数据是try/catch中操作后数据。即finally操作后的数据存储到其他槽中,而后再加载try/catch操作后的数据。

而在finally中含有return时,栈中最后存储的数据是finally中操作后的数据。即finally操作后的数据存储到其他槽中,而后加载的是其他槽(finally)中的数据。

也就是说:如果finally中不含有return语句,finally对try/catch操作的八大基础类型不会再加载到操作数栈中。

如果返回值是对象引用,finally中的return还有待考据。

参考:关于 Java 中 finally 语句块的深度辨析
更多文章:http://blog.gavinzh.com

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
Java 项目中如何使用异常
1.早抛出,晚捕获.2.如果finally语句中有return语句,则finally中的return语句将会覆盖try中的return语句,如以下代码,将会输出1。如果在finally语句里有抛出异常,那么此异常将会覆盖try块中抛出的异常。publicclassFinallyReturnTest{
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
Java笔试面试总结—try、catch、finally语句中有return 的各类情况
前言之前在刷笔试题和面试的时候经常会遇到或者被问到trycatchfinally语法块的执行顺序等问题,今天就抽空整理了一下这个知识点,然后记录下来。正文本篇文章主要是通过举例的方式来阐述各种情况,我这里根据trycatchfinally语法块分为两种大情况讨论:trycatch语法块和trycat
Stella981 Stella981
3年前
Python从入门到入土
异常处理tryexcept在Python中,异常处理,主要是tryexcept语句,通常语法格式如下.try:代码块1exceptExceptionase:print(e)代码2try语句按照如下方式工作;首先,执行try子句(在关键字try和关键字except之间的语句)如果没有异常
Stella981 Stella981
3年前
Return出现在try、catch、finally中的不同执行结果
前几天,去一家公司面试,碰到一道面试题大致内容为:如果在try中存在return语句,那么finally中的语句是否会执行,如果会执行,那先后顺序又是怎样。当时自己的解题思路是:坚信大学时候,java编程基础的一句话,finally中的语句一定会执行,所以我觉得finally中的语句一定会执行,而return语句会跳出当前方法,所以return语句应该在
小万哥 小万哥
1年前
Python 异常处理:try、except、else 和 finally 的使用指南
异常处理当发生错误(或我们称之为异常)时,Python通常会停止执行并生成错误消息。try块用于测试一段代码是否存在错误。except块用于处理错误。else块用于在没有错误时执行代码。finally块用于无论try和except块的结果如何都要执行的代码