https://blog.csdn.net/csdn_bang/article/details/86662998
1、finally是在return語句執行之後,return語句傳回之前,finally是必執行的(當然是建立在try執行的基礎上);
2、finally中修飾的基本類型沒有return是不影響傳回結果的,有了return才會影響傳回結果;
3、finally中修改set、list、map引用類型時,就算沒有return也會影響傳回結果;
package com;
import java.util.ArrayList;
import java.util.List;
/**
* @author wanjiadong
* @date Create in 14:26 2019/2/13
*/
public class finallytest {
public static void main(String[] args) {
int j = test1();
System.out.println("j=" +j);
List<String> cats = new ArrayList<>();
cats = addCats(cats);
assert cats != null;
cats.forEach(System.out::println);
}
private static int test1() {
int i = 0;
try {
System.out.println("try");
return i+=10;
} catch (Exception e) {
e.printStackTrace();
return i;
} finally {
System.out.println("finally i =" + i);
i+=10;
System.out.println("finally ii="+i);
return i;
}
}
private static List<String> addCats(List<String> cats) {
try {
cats.add("a");
return cats;
} catch (Exception e) {
e.printStackTrace();
} finally {
cats.add("b");
}
System.out.println("out");
return null;
}
}
在JVM虛拟機種,有虛拟機棧,上面的代碼中每一個方法都對應了一個棧幀,方法的執行對應的棧幀入棧,方法的執行完畢對應着棧幀的出棧。
棧幀可以了解為一個方法的運作空間。它主要由兩部分構成,一部分是局部變量表,方法中定義的局部變量以及方法的參數就存放在這張表中;另一部分是操作數棧,用來存放操作數。
剛才的兩段代碼中的finally塊中,i變量是要放到局部變量表的,每次有關于i的運算,都是要把i從局部變量表取出來(可以了解為copy一個副本),比如i += 10,那麼需要把i和10都放到操作數棧中進行計算,然後得到一個結果,而這個結果是需要通過retrun語句寫回到局部變量表。
第一段代碼中的finally塊中,雖然執行了i += 10,但是由于沒有return,是以局部變量表中的内容沒有變化,是以i還是10;
第二段代碼中的finally塊中,由于最後return i語句的執行,更新了局部變量中的i的值,是以最後傳回的結果中i就是20了。
return傳回後,就代表着方法執行結束,相應的該方法的棧幀就出棧了。而這個時候也就意味着,return傳回是最後執行的,是以finally語句是在retrun傳回之前執行的!