finally與return之間的關係

定論

問:finally語句必定會執行嗎?java

答:佈局

1.若是沒有執行相應的try語句則不會執行。spa

2.在try語句中若是調用System.exit(0)方法則不會執行。.net

 

問:finally會在何時執行?code

答:若是在try/catch語句中調用轉移指令例如:return,break,continue,throw等。則會在轉移指令前執行。對象

 

總結

finally與return之間的關係blog

若是在finally中含有return語句,那麼try/catch語句的return還有做用嗎?內存

先看一段代碼:get

/**
 * 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/

 

更多文章:http://blog.gavinzh.com

相關文章
相關標籤/搜索