Java: on the difference between return and throw in catch statement blocks in try-catch-finally

in the following example

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
    }
    

statement 2 executes before statement 1. The result is that Name is baga age is: 3
statement 1 returns the following:
Name is lily age is: 3
, which means that return is a deep copy of s, and s cannot be affected by finally blocks

.

Grammar Sugar 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){
        ...
    }
   

where we see

in the catch block
t=t1;
throw t1;
      

then the following:

t.addSuppressed(t2);

T2 can be carried by the T1 that can be thrown, indicating that throw T1 retains a shallow copy and can be affected by finally blocks

.

what is the difference?

Mar.23,2021

this is not the case. In fact, the s.toString () in the catch block executes first, then the contents of the finally block, and then the return. So, the final return is actually the content of the s before the execution of the finally block.


clipboard.png

clipboard.png

these two figures can clearly see the difference between the two. In the first example, the final return value has been calculated before the instruction areturn, and setName is called after the instruction areturn; the second example is normal execution, and addSuppressed is called before return. It is suggested that the subject analyze it from the perspective of jvm instruction.

post my code:

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);
    }

}
Menu