鍍金池/ 問答/Java/ Java: 關(guān)于try-catch-finally中catch語句塊里retur

Java: 關(guān)于try-catch-finally中catch語句塊里return和throw的差別問題

下面的例子中

Student s = new Student("lily", 3);  //name, age
    try{
        int i = 3;
        int j = i/0;
        return s.toString();
    }catch (Exception e){
        Student t = s;
        return t.toString();               // 語句1
    }finally {
        s.setName("baga");
        System.out.println(s.toString());   // 語句2
    }
    

語句2先于語句1執(zhí)行,結(jié)果是 Name is baga age is: 3
語句1返回的是:
Name is lily age is: 3
這說明return的是s的一個深拷貝,s不能被finally塊影響了

語法糖try with resource

    try(FileInputStream fis = new FileInputStream(file)){
        fis.read();
    } catch (IOException e3){
        ...
    }
    
反編譯其實就是

    try{
        FileInputStream fis = new FileInputStream(file);
        Throwable t = null;
        try{
            fis.read();
        }catch (Throwable t1){
            t = t1;
            throw t1;
        }finally {
            if(fis != null){
                if(t != null){
                    try {
                        fis.close();
                    }catch (Throwable t2){
                        t.addSuppressed(t2); 
                    }
                }
                else {
                    fis.close();
                }
            }
        }
    }catch (IOException e3){
        ...
    }
   

其中我們看到catch塊中

t=t1;
throw t1;
      

然后下面:

t.addSuppressed(t2);

t2能被拋出的t1攜帶,說明 throw t1保留的是一個淺拷貝,能被finally塊影響

這個區(qū)別是為何?

回答
編輯回答
妖妖

clipboard.png

clipboard.png

這兩張圖可以清楚的看出來這兩者之間的區(qū)別了,第一個例子中,在areturn這個指令之前,已經(jīng)計算出了最后的返回值,setName是在areturn這個指令之后調(diào)用;第二個例子,就是正常執(zhí)行,addSuppressed是在return之前調(diào)用。建議題主從jvm指令這個角度分析一下。

貼出我的代碼:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.junit.Test;

public class TestExample {
    public static class Student {
        private String name;
        private int age;

        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return "Name is " + name + " age is " + age;
        }

        public void setName(String string) {
            this.name = string;
        }

    }

    public String get() {
        Student s = new Student("lily", 3); // name, age
        try {
            int i = 3;
            int j = i / 0;
            return s.toString();
        } catch (Exception e) {
            Student t = s;
            return t.toString(); // 語句1
        } finally {
            s.setName("baga");
            System.out.println(s.toString()); // 語句2
        }
    }

    @Test
    public void test1() {
        try {
            File file = new File("");
            FileInputStream fis = new FileInputStream(file);
            Throwable t = null;
            try {
                fis.read();
            } catch (Throwable t1) {
                t = t1;
                throw t1;
            } finally {
                if (fis != null) {
                    if (t != null) {
                        try {
                            fis.close();
                        } catch (Throwable t2) {
                            t.addSuppressed(t2);
                        }
                    } else {
                        fis.close();
                    }
                }
            }
        } catch (IOException e3) {

        }
    }

    @Test
    public void test() {
        String result = get();
        System.out.print(result);
    }

}
2017年12月24日 01:33
編輯回答
心沉

不是這樣的。其實是catch塊里面的s.toString()先執(zhí)行,再執(zhí)行finally塊里的內(nèi)容,然后再執(zhí)行return。所以,最后返回的內(nèi)容其實是為執(zhí)行finally塊之前的s的內(nèi)容。

2017年2月22日 12:08