资讯专栏INFORMATION COLUMN

finally与return之间的关系

Yuanf / 1066人阅读

摘要:则会在转移指令前执行。总结与之间的关系如果在中含有语句,那么语句的还有作用吗先看一段代码如果你对内存布局不是很清楚,请看这篇文章虚拟机类加载机制和字节码执行引擎重点关注运行时栈帧结构局部变量表槽,操作数栈。

定论

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

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

在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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64459.html

相关文章

  • java内存模型

    摘要:顺序一致性内存模型有两大特性一个线程中所有操作必须按照程序的顺序执行。这里的同步包括对常用同步原语的正确使用通过以下程序说明与顺序一致性两种内存模型的对比顺序一致性模型中所有操作完全按程序的顺序串行执行。 java内存模型 java内存模型基础 happen-before模型 JSR-133使用happen-before的概念来阐述操作之间的内存可见性。在JMM中,如果一个操作执行的结...

    2i18ns 评论0 收藏0
  • 深入理解Java内存模型(六)——final

    摘要:对于域,编译器和处理器要遵守两个重排序规则在构造函数内对一个域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。这个屏障禁止处理器把域的写重排序到构造函数之外。下一篇深入理解内存模型七总结 与前面介绍的锁和volatile相比较,对final域的读和写更像是普通的变量访问。对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个fi...

    lixiang 评论0 收藏0
  • 聊聊Tomcat架构设计

    摘要:本篇文章主要是跟大家聊聊的内部架构体系,让大家对有个整体的认知。方法会创建一个对象,调用它的方法将字节流封装成对象,在创建组件时,会将组件添加到组件中组件而组件在连接器初始化时就已经创建好了目前为止,只有一个实现类,就是。 微信公众号「后端进阶」,专注后端技术分享:Java、Golang、WEB框架、分布式中间件、服务治理等等。 老司机倾囊相授,带你一路进阶,来不及解释了快上车! T...

    cnio 评论0 收藏0
  • 《深入理解 Java 内存模型》读书笔记

    摘要:前提深入理解内存模型程晓明著,该书在以前看过一遍,现在学的东西越多,感觉那块越重要,于是又再细看一遍,于是便有了下面的读书笔记总结。同步同步是指程序用于控制不同线程之间操作发生相对顺序的机制。线程之间的通信由内存模型控制。 showImg(https://mmbiz.qpic.cn/mmbiz_jpg/1flHOHZw6RtPu3BNx3zps1JhSmPICRw7QgeOmxOfTb...

    姘存按 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<