天天看點

finally到底是在return之前執行還是return之後執行?

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傳回之前執行的!