try-catch-finally&return執(zhí)行順序引發(fā)的思考[網(wǎng)易云課堂-微專業(yè)-Java]

前言

??前一段時間校招閱卷,發(fā)現(xiàn)一道有關(guān)try-catch-finally&return執(zhí)行順序題目,其實之前也有遇到,一直沒太在意,現(xiàn)總結(jié)記錄,并記錄有該題目引發(fā)有關(guān)基礎(chǔ)的思考——為何說java是值調(diào)用,而非引用調(diào)用。

具體題目

public class tryCatch {

    public static void main(String[] args) {
        int a = 1, b = 1;
        System.out.println(add(a++, ++b));
    }
    public static int add(int a, int b) {
        int c = a + b;
        try {
            return c;
        } finally {
            System.out.println("finally語句塊");
            c = 0;
        }
    }
}

??上述的執(zhí)行結(jié)果如下:

執(zhí)行結(jié)果.png

結(jié)果分析

??執(zhí)行順序想必都是沒有疑問的,因為我們都知道finally中的代碼總會被執(zhí)行,即:任何執(zhí)行try 或者catch中的return語句之前,都會先執(zhí)行finally語句,如果finally存在的話。如果finally中有return語句,那么程序就return了,所以finally中的return是一定會被return的,編譯器把finally中的return視為為一個warning【所以釋放資源的代碼一般放在finally中】。問題在于:為何最終結(jié)果是3?

??在思考這個問題前,我又陸續(xù)做了以下幾個實驗:

  • 1、 try中帶有return
public static void main(String[] args) {
        //int a = 1, b = 1;
        //System.out.println(add(a++, ++b));
        int i=testReturn1() ;
        System.out.println("i:"+i);
    }
private static int testReturn1() {
        int i = 1;
        try {
            i++;
            System.out.println("try:" + i);
            return i;
        } catch (Exception e) {
            i++;
            System.out.println("catch:" + i);
            return i;
        } finally {
            i++;
            System.out.println("finally:" + i);
        }
    }

??上述的執(zhí)行結(jié)果如下:

執(zhí)行結(jié)果.png
  • 2、非基本類型
  public static void main(String[] args) {
        //int a = 1, b = 1;
        //System.out.println(add(a++, ++b));
        //int i=testReturn1() ;
        //System.out.println("i:"+i);
        List<Integer> list=testReturn2();
        System.out.println("list:"+list);
    }
  private static List<Integer> testReturn2() {
        List<Integer> list = new ArrayList<>();
        try {
            list.add(1);
            System.out.println("try:" + list);
            return list;
        } catch (Exception e) {
            list.add(2);
            System.out.println("catch:" + list);
            return list;
        } finally {
            list.add(3);
            System.out.println("finally:" + list);
        }
    }

??上述的執(zhí)行結(jié)果如下:

執(zhí)行結(jié)果.png
  • 3、catch中帶有return
 public static void main(String[] args) {
        //int a = 1, b = 1;
        //System.out.println(add(a++, ++b));
        int i=testReturn3() ;
        System.out.println("i:"+i);
        //List<Integer> list=testReturn2();
        //System.out.println("list:"+list);
    }
  private static int testReturn3() {
        int i = 1;
        try {
            i++;
            System.out.println("try:" + i);
            int x = i / 0 ;
        } catch (Exception e) {
            i++;
            System.out.println("catch:" + i);
            return i;
        } finally {
            i++;
            System.out.println("finally:" + i);
        }
        return i;
    }

??上述的執(zhí)行結(jié)果如下:

執(zhí)行結(jié)果.png
  • 4、finally中帶有return
public static void main(String[] args) {
        //int a = 1, b = 1;
        //System.out.println(add(a++, ++b));
        int i=testReturn4() ;
        System.out.println("i:"+i);
        //List<Integer> list=testReturn2();
        //System.out.println("list:"+list);
    }
 private static int testReturn4() {
        int i = 1;
        try {
            i++;
            System.out.println("try:" + i);
            return i;
        } catch (Exception e) {
            i++;
            System.out.println("catch:" + i);
            return i;
        } finally {
            i++;
            System.out.println("finally:" + i);
            return i;
        }
    }

??上述的執(zhí)行結(jié)果如下:

執(zhí)行結(jié)果.png

基于上述實驗的總結(jié)與思考

  • finally中的代碼總會被執(zhí)行。
  • 當try、catch中有return時,也會執(zhí)行finally。return的時候,要注意返回值的類型,是否受到finally中代碼的影響。
  • finally中有return時,會直接在finally中退出,導(dǎo)致try、catch中的return失效。
  • 重點來了:讓我們仔細對比 上述 案例中的 1 & 2.
    ??我們都知道:java方法參數(shù)共有2種,即:基本數(shù)據(jù)類型與對象引用。根據(jù)《Java核心技術(shù)》一書中,我們知道,Java是按照值調(diào)用的,即:方法得到的所有參數(shù)值都是一根拷貝,特別是:方法不能修改傳遞給它的任何參數(shù)變量的內(nèi)容。這時有人會反駁:那么參數(shù)是集合類型的,內(nèi)容為何會被修改?注意了:因為傳入的是該集合的引用,通過該引用可以改變該引用指向的內(nèi)容,但是該引用是沒有被修改的。
    ??有了上面的共同認知,我們繼續(xù)。對于1 & 2都是在一個方法里,為何基本數(shù)據(jù)類型和引用數(shù)據(jù)類型結(jié)果不那么一致呢?【從結(jié)果上看,基本數(shù)據(jù)類型,finally對于局部變量的操作無效,】這里大膽猜測,注意是猜測。有木有發(fā)現(xiàn):try & finally分別擁有一個語句塊:{ }。
    ??上述的運行順序應(yīng)該如下:
fun():
  var x=0
  var y=fun1(x)
  fun2(y)
  return y
fun1(var x):
  x++
  return x
fun2(var y):
  y++

??其中,fun1相當于try代碼塊的執(zhí)行,fun2相當于finally代碼塊的執(zhí)行。你品,仔細品。如果是引用類型是不是fun2就有效,基本數(shù)據(jù)類型就不會生效呢?[切記:Java是值調(diào)用!也就是說fun2中對于y的修改其實沒有修改y,是自己的棧內(nèi)有一新的變量,其值=y++,但是fun1的y不受其影響]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容