finally与return之间的关系

定论

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

答:

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

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

问:finally会在什么时候执行?

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

总结

如果在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虚拟机类加载机制和字节码执行引擎 http://my.oschina.net/jiangmitiao/blog/483824

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

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

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://www.ibm.com/developerworks/cn/java/j-lo-finally/

时间: 2024-08-29 19:32:59

finally与return之间的关系的相关文章

Spring学习--Bean 之间的关系

Bean 之间的关系:继承.依赖. Bean 继承: Spring 允许继承 bean 的配置 , 被继承的 bean 称为父 bean , 继承这个父 bean 的 bean 称为子 bean. 子 bean 从父 bean 中继承配置 , 包括 bean 的属性配置. 子 bean 也可以覆盖从父 bean 继承过来的配置. 父 bean 可以作为配置模板 , 也可以作为 bean 实例.若只想把父 bean 作为模板 , 可以设置 <bean> 的 abstract 属性为 true ,

windows 程序的本体与操作系统之间的关系

1 WinMain(hInst,hPrev,--) 2 { 3 MSG msg; 4 RegisterClass(--); 5 CreateWindow(--); 6 ShowWindow(--); 7 UpdateWindow(--); 8 while(GetMessage(--)) 9 { 10 TranslateMessage(--); 11 DispatchMessage(--); 12 } 13 return msg.wParam; 14 } 15 16 Window Procedur

java 类与类之间的关系 及uml图

类与接口之间的关系 : 继承 类与类之间的关系 :继承关系  包含关系 类与对象之间的关系 : 实例 UML 类图中类与类之间的关系: 泛化关系(generalization) 关联关系(association) 聚合关系(aggregation) 合成关系 (compostion) 依赖关系 (dependency) 1.泛化(Generalization)[泛化]表示类与类之间的继承关系,接口与接口之间的继承关系,或类对接口的实现关系.一般化的关系是从子类指向父类的,与继承或实现的方法相反.

Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系

一.Surface Surface就是“表面”的意思.在SDK的文档中,对Surface的描述是这样的:“Handle onto a raw buffer that is being managed by the screen compositor”,翻译成中文就是“由屏幕显示内容合成器(screen compositor)所管理的原生缓冲器的句柄”,这句话包括下面两个意思: 1.      通过Surface(因为Surface是句柄)就可以获得原生缓冲器以及其中的内容.就像在C语言中,可以通

1,对象的存储细节,2,#pragma mark指令,3,函数和对象方法的区别,4,对象和方法之间的关系 ,5.课堂习题

1,对象的存储细节, 1. 当创建一个对象的时候:Person *p1 = [Person new],做了三件事情: 1,申请堆内存空间: 2,给实例变量初始化: 3,返回所申请空间的首地址; 2. 实例变量保存在堆区 3. 对象方法保存在代码区 4. 一个类可以创建多个对象: 2,#pragma mark指令, 功能:对代码分组,方便代码查找和导航 使用格式: #pragma mark - #waring 等待处理的功能,或者是未完成的功能 3,函数和对象方法的区别, 一. 对象方法: -(v

06.实现servlet的几种方式,以及接口或者类之间的关系

接口:Servlet.ServletConfig.ServletRequest.ServletResponse.HttpServletRequest.HttpServletResponse.ServletContext 类:HttpServlet(抽象类).GenericServlet(抽象类) 来张关系图 ServletContext: ServletContext的对象是application是在项目初始化时被创建的.故servletContext随着应用初始化而被创建,随着应用的结束而被销

峰Spring4学习(5)bean之间的关系和bean的作用范围

一.bean之间的关系: 1)继承: People.java实体类: package com.cy.entity; public class People { private int id; private String name; private int age; private String className; public int getId() { return id; } public void setId(int id) { this.id = id; } public Strin

李洪强iOS开发之OC[018]对象和方法之间的关系

// //  main.m //  18 - 对象和方法之间的关系 // //  Created by vic fan on 16/7/14. //  Copyright © 2016年 李洪强. All rights reserved. // /** * OC有参有返回值的方法 有参有返回值方法的声明 - (int)sum:(int)x andY:(int)y; - (int)sum:(int)x andY:(int)y{ return x+y; 关系: 1 对象作为方法的参数; 显示人的信息

[转] valuestack,stackContext,ActionContext.之间的关系

三者之间的关系如下图所示: ActionContext  一次Action调用都会创建一个ActionContext  调用:ActionContext context = ActionContext.getContext() ValueStack 由OGNL框架实现  可以把它简单的看作一个List Stack Object:放入stack中的对象,一般是action. Stack Context(map):stack上下文,它包含一些列对象,包括request/session/attr/ap