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

前言

??前一段時(shí)間校招閱卷,發(fā)現(xiàn)一道有關(guān)try-catch-finally&return執(zhí)行順序題目,其實(shí)之前也有遇到,一直沒太在意,現(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í)行順序想必都是沒有疑問的,因?yàn)槲覀兌贾纅inally中的代碼總會(huì)被執(zhí)行,即:任何執(zhí)行try 或者catch中的return語句之前,都會(huì)先執(zhí)行finally語句,如果finally存在的話。如果finally中有return語句,那么程序就return了,所以finally中的return是一定會(huì)被return的,編譯器把finally中的return視為為一個(gè)warning【所以釋放資源的代碼一般放在finally中】。問題在于:為何最終結(jié)果是3?

??在思考這個(gè)問題前,我又陸續(xù)做了以下幾個(gè)實(shí)驗(yàn):

  • 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

基于上述實(shí)驗(yàn)的總結(jié)與思考

  • finally中的代碼總會(huì)被執(zhí)行。
  • 當(dāng)try、catch中有return時(shí),也會(huì)執(zhí)行finally。return的時(shí)候,要注意返回值的類型,是否受到finally中代碼的影響。
  • finally中有return時(shí),會(huì)直接在finally中退出,導(dǎo)致try、catch中的return失效。
  • 重點(diǎn)來了:讓我們仔細(xì)對(duì)比 上述 案例中的 1 & 2.
    ??我們都知道:java方法參數(shù)共有2種,即:基本數(shù)據(jù)類型與對(duì)象引用。根據(jù)《Java核心技術(shù)》一書中,我們知道,Java是按照值調(diào)用的,即:方法得到的所有參數(shù)值都是一根拷貝,特別是:方法不能修改傳遞給它的任何參數(shù)變量的內(nèi)容。這時(shí)有人會(huì)反駁:那么參數(shù)是集合類型的,內(nèi)容為何會(huì)被修改?注意了:因?yàn)閭魅氲氖窃摷系囊茫ㄟ^該引用可以改變?cè)撘弥赶虻膬?nèi)容,但是該引用是沒有被修改的。
    ??有了上面的共同認(rèn)知,我們繼續(xù)。對(duì)于1 & 2都是在一個(gè)方法里,為何基本數(shù)據(jù)類型和引用數(shù)據(jù)類型結(jié)果不那么一致呢?【從結(jié)果上看,基本數(shù)據(jù)類型,finally對(duì)于局部變量的操作無效,】這里大膽猜測(cè),注意是猜測(cè)。有木有發(fā)現(xiàn):try & finally分別擁有一個(gè)語句塊:{ }。
    ??上述的運(yùn)行順序應(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相當(dāng)于try代碼塊的執(zhí)行,fun2相當(dāng)于finally代碼塊的執(zhí)行。你品,仔細(xì)品。如果是引用類型是不是fun2就有效,基本數(shù)據(jù)類型就不會(huì)生效呢?[切記:Java是值調(diào)用!也就是說fun2中對(duì)于y的修改其實(shí)沒有修改y,是自己的棧內(nèi)有一新的變量,其值=y++,但是fun1的y不受其影響]

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

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