Java中try.catch.finally执行顺序问题」

一、写在前面

最近在Review代码的时候发现了小伙伴出现了比较粗心的代码,在finally中作了return操作。因为Kotlin实在是太香了kotlin是什么Java的一些东西可能都已经淡忘了。这里重新整理一下也提醒一下自己平时多注意这些kotlin和java区别细节,原代码是这样的

public String getStr(ParamVO paramVO) {
  try {
    //fixme do something
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    return ""
  }
}

这段代码的想法很好理解,在t测试用例ry内部可能有异常的情况发生,当发生异常的情况时,希望通过finally中的return语句操作返回一个空字符串,以不至于使程序崩溃。但是这里已经是没有理解,finally的执行时机,以及finally块中存在return情况下的值返回情况。而平时在开发过程中,大多数接触到finally的情景基本都是在操作IO流时对流的关闭操作。那么finally的执行时机,以及fijava语言nally块中包含return时的值返回情况到底是怎样的呢?一起来了测试你的自卑程度解一下。

二、所有情况

罗列出所有的tryfinally以及return的情况,主要javascript分为如下几种,分别讨论每一种情况:

  • A. tryfinally中均包含return字段
  • B. try中包含return字段,finally中没有,并且不修改待返回的值
  • C. try测试抑郁程度的问卷包含return字段,finally中没有,并且修改待返回的值(基本数据类型)
  • D. try中包含rjava语言eturn字段,finally中没有测试抑郁症,并且修改待返回的值(对象的属性)
三、分情况讨论
1.情况A tryfinally中均包含return字段

测试代码为例如下:

public class ReturnTest {
  public static void main(String[] args) {
    System.out.println("result = " + getStr(10));
  }
  private static int getStr(int number) {
    try {
      ++number;
      System.out.println("try was executed");
      return number;
    } catch (Exception e) {
      e.printStackTrace();
      System.out.println("catch was executed");
      number += 10;
      return number;
    } finally{
      System.out.println("finally was executed");
      number += 100;
      return number;
    }
  }
}

tryfinally字节码都包含return语句,那么执行字符是什么后的返回值是多少呢?11还是101又或者是111?直观上看这不是肯定返回11嘛,没有发生异常catch不会被执行,执行到try中,自增操作然后返回,很明显测试用例结果是11啊。看一下打印的信息:

try was executed
finally was executed
result = 111
Process finished with exit code 0

意不意外惊不惊字节码文件扩展名喜,结果上看,在try中参数10被自增加1,但是此时值并没有返回。而是执行到finally中,并且测试手机是否被监控try的结果之上自增了100,因此最终结果kotlin语言111,并且返回的结果为111try中的return没有被最终执行。当然这里改变的是基本数据类型,那么如果是对象kotlin为什么流行不起来的属性值呢?是否一样会被覆盖呢?看第二个测试代码,新增一个UserVO对象:kotlin和java区别

public class UserVO {
    private int age;
    private String name;
    private String address;
    public UserVO(int age, String name) {
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "UserVO{" +
                "age=" + age +
                ", name='" + name + ''' +
                ", address='" + address + ''' +
                '}';
    }
}

修改一下测试代码:

private static UserVO getStr(UserVO userVO) {
  if (null == userVO) {
    return null;
  }
  try {
    userVO.setName("sai");
    System.out.println("try was executed");
    return userVO;
  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("catch was executed");
    userVO.setName("apple");
    return userVO;
  } finally{
    System.out.println("finally was executed");
    userVO.setName("mac");
    return userVO;
  }
}
//main 方法中
public static void main(String[] args) {
  System.out.println("result = " + getStr(10));
  System.out.println("--------------------------------");
  UserVO userVO = new UserVO(5, "sai");
  System.out.println("result = " + getStr(userVO));
}

这里在finally中对UserVO对象中java环境变量配置的属性na字符型变量me作了修改并返回了对象,按照之前的测试用例,代码执行到finally直接返回,那么UserVO中的name属性应该同样会被覆盖并且跟是否是基本数据类型或者kotlin和java是对象没有关系。看一下打印的信息:

try was executed
finally was executed
result = 111
--------------------------------
try was executed
finally was executed
result = UserVO{age=5, name='mac', address='null'}
Process finished with exit code 0

结果很明显,跟猜测的结果字符串是什么意思是一样的,属性的值同样会被覆盖了,那么可以得出结论:

  • try字节码是什么意思finally均包含return操作时,无论返回值是基本数据类型kotlin怎么读还是对象,返回值都会被finally中操作覆盖,当然如果是基本数据类型,finally测试抑郁症的操作是基于在try中操作后的基础上。
2. 情况C、D try中包含return字段,fina字符lly中没有,并且修改待返回的值(属性)

还是以为上述的代码测试,这里将finally中的return操作删除,分别测试对基本数据类型与对象的操作,来看看最终的结果是什么样子测试仪的。首先以基本数据类java模拟器型为例,修改后的代码:

private static int getStr(int number) {
  try {
    ++number;
    System.out.println("try was executed");
    return number;
  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("catch was executed");
    number += 10;
    return number;
  } finally{
    System.out.println("finally was executed");
    number += 100;
    System.out.println("finally was executed" + "number = " + number);
    //return number;
  }
}
//main method
public static void main(String[] args) {
  System.out.println("result = " + getStr(10));
}

那么此kotlin语言时返回的是11还是111呢?答案是11

try was executed
finally was executed
finally was executednumber = 111
result = 11

这里虽然结果为11,但是可以发现的是,在finally块中,number的值还是被增加了,只不过由于finally中没有返回字段,而返回了try中值11。其实finally中的操作明显是在tryreturn操作之前。现在即使不测试对UserVOname属性的修改应该也可以猜到,对于对象中的属性会被finally所覆盖。因为finally块中的操作是先于tryreturn字段之前的(如果try中包含有return字段),对于对象的属性修改,即使finally不返回,try中返回的属性也是被finally修改过后的值。看测试用例:

private static UserVO getStr(UserVO userVO) {
  if (null == userVO) {
    return null;
  }
  try {
    userVO.setName("sai");
    System.out.println("try was executed");
    return userVO;
  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("catch was executed");
    userVO.setName("apple");
    return userVO;
  } finally{
    System.out.println("finally was executed");
    userVO.setName("mac");
   //return userVO;
  }
}
//main
public static void main(String[] args) {
    UserVO userVO = new UserVO(5, "sai");
    System.out.println("result = " + getStr(userVO));
}

打印的信息如下字符是什么

try was executed
finally was executed
result = UserVO{age=5, name='mac', address='null'}
Process finished with exit code 0

可以看到确确测试实实是被finally测试英文中的操作覆Java盖了。可以得出结论:

  • try中包含有returnfinally没有,并且finally块中作值的修改,或者对象的属性修改时;对于基本数据类型如int,即使finally中修改值,返回结果依然是try中期望计算的结果值。但是如果为对象的属性,那么返回的结果会与try中的结果有偏差,期望结果(属性值)被finally中的修改所覆盖。
3.情况B try中包含return字段,finally中没字符间距在哪里设置有,并且不修改待返回的值
  • 这种情测试抑郁程度的问卷况比较简单,理论上这种仅仅是打印一些Log信息,finally中没有return字段同时也不对待返回值进行修改,那么返回值就是try中计算或者操作的期望值。但是需要注意的是,finally的操作是先tryreturn操作之前完成的。
四、异常情况

上面讨论了正常的情况,try块中正常执行没有异常的情况,那么如果try中如字符间距果存在异常,执行顺序与返回值会是什么情况呢?来看看异常的情况。分别对上述A、B、C、D四种情况加上异常。

1.情况A tryfinally中均包含return字段(try中抛出异常)

修改测试代码如下:

private static int getStr(int number) {
  try {
    ++number;
    System.out.println("try was executed");
    //return number;
    throw new Exception("模拟异常的情况");
  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("catch was executed");
    number += 10;
    return number;
  } finally{
    System.out.println("finally was executed");
    number += 100;
    System.out.println("finally was executed" + "number = " + number);
    return number;
  }
}
//main 
public static void main(String[] args) {
  System.out.println("result = " + getStr(10));
  System.out.println("--------------------------------");
}

此时是不是跟正常情况一样呢?catch的值被finalkotlin匿名函数ly所覆盖?看一下打印的结果:

try was executed
catch was executed
finally was executed
finally was executednumber = 121
result = 121
--------------------------------
java.lang.Exception: 模拟异常的情况
	at main.test.ReturnTest.getStr(ReturnTest.java:21)
	at main.test.ReturnTest.main(ReturnTest.java:10)
Process finished with exit code 0

可以发现结果跟预想的是一样的,当try中发生异常情况,代码执行到catch中,并且对n字符间距在哪里设置umber执行了自增操作赋值此时,number = 21,因为trynumber被增加了1,当然这种情java语言况不是确定的,具体的还的看代kotlin怎么读码实现Java。当catch中被赋值后并没有直接返回结果,而是执行到finally中并且返回了最终的结果121。由此可以得出结论:

  • tryfinally均包含return操作时,并且try测试用例存在异常,在catch中即使对基本数据类型数据进行操作,返回值还是会被fina测试抑郁症lly所覆盖。

测试你适合学心理学吗么对于对象的属性修改是不是同样的呢?修改测试抑郁程度的问卷测试代码测试仪,继续来一下打印的信息:

private static UserVO getStr(UserVO userVO) {
  if (null == userVO) {
    return null;
  }
  try {
    userVO.setName("sai");
    System.out.println("try was executed");
    throw new Exception("模拟异常的情况");
    // return userVO;
  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("catch was executed");
    userVO.setName("apple");
    return userVO;
  } finally{
    System.out.println("finally was executed");
    userVO.setName("mac");
    return userVO;
  }
}
//main 
public static void main(String[] args) {
  UserVO userVO = new UserVO(5, "sai");
  System.out.println("result = " + getStr(userVO));
}
//打印信息
try was executed
catch was executed
finally was executed
result = UserVO{age=5, name='mac', address='null'}
java.lang.Exception: 模拟异常的情况
	at main.test.ReturnTest.getStr(ReturnTest.java:44)
	at main.test.ReturnTest.main(ReturnTest.java:13)
Process finished with exit code 0

其实结论是一样的,属性依然是最终被finally所覆盖了,修改字符间距加宽2磅一下结论:

  • tryfinally均包含return操作时,并且try中存在异常,在catch中即使对基本数据类型数据进行操作或者对对象属性的修改Java,返回值还是会被finally所覆盖。
2.情况java环境变量配置C、D try中包含return字段,finally中没有,Kotlin并且修改待返回的值(属性),并且try抛出异测试英文

直接修改测试代码,去掉finallyreturn字段:

//基本数据类型
private static int getStr(int number) {
  try {
    ++number;
    System.out.println("try was executed");
    //return number;
    throw new Exception("模拟异常的情况");
  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("catch was executed");
    number += 10;
    return number;
  } finally{
    System.out.println("finally was executed");
    number += 100;
    System.out.println("finally was executed" + "number = " + number);
    //return number;
  }
}
//对象的属性
private static UserVO getStr(UserVO userVO) {
  if (null == userVO) {
    return null;
  }
  try {
    userVO.setName("sai");
    System.out.println("try was executed");
    throw new Exception("模拟异常的情况");
    // return userVO;
  } catch (Exception e) {
    e.printStackTrace();
    System.out.println("catch was executed");
    userVO.setName("apple");
    return userVO;
  } finally{
    System.out.println("finally was executed");
    userVO.setName("mac");
    //return userVO;
  }
}
//main
public static void main(String[] args) {
  System.out.println("result = " + getStr(10));
  System.out.println("--------------------------------");
  UserVO userVO = new UserVO(5, "sai");
  System.out.println("result = " + getStr(userVO));
}
//打印的信息
try was executed
catch was executed
finally was executed
finally was executednumber = 121
result = 21
--------------------------------
try was executed
catch was executed
finally was executed
result = UserVO{age=5, name='mac', address='null'}
java.lang.Exception: 模拟异常的情况
	at main.test.ReturnTest.getStr(ReturnTest.java:21)
	at main.test.ReturnTest.main(ReturnTest.java:10)
java.lang.Exception: 模拟异常的情况
	at main.test.ReturnTest.getStr(ReturnTest.java:44)
	at main.test.ReturnTest.main(ReturnTest.java:13)
Process finished with exit code 0

finally中没有return字段,这里分别对基本数据类型以及对象属性进行测试,在try中抛出异常,虽然在cat测试抑郁症的20道题ch中对字段、属性重新赋值,但是同时也在finally进行修改。可以发现情况与try正常情况是一致的,即对于基本数据类型期望值以catch为准,而对象java培训属性在经过finally操作后依然会被覆盖了。为什么会存在上述这些情况呢?那具体的代码执行流程就需javaee要借助字节码信息了,看看到底是怎样执行的。

五、字节码信息

字符间距在哪里设置Java自带的工具,在终端Terminal可以直接将 .java文件编译成 .class文件,命令javascript

 javac xxxxxxx.java

这里使用的编译器是IDEA,存在一个小问题Kotlin,会提示 找不到文件,只需要在移动到当前待编译的Java文件目录下执行命令就可以了。得到 .cl字符间距ass文件后,执行命令:

javap -verbose -p xxxxxx.class

就可以在终端中显示具体的信息了,这里只截取了几个关键的信息,方便查看:

「Java中try.catch.finally执行顺序问题」

其中iinc表示自增操作,至于其他的信息可java培训以对照字节码表对照来测试手机是否被监控看,主要关心的是为什么,finally的执行顺序以及存在return时的执行机制。字符串逆序输出观察字节码信息,可以发现,明明我们只写了一个finally,但是编译测试你适合学心理学吗后为什么会存在三处finally?稍加思考就可以明白,这其实是为了保证finally一定会被执行到。注意是一定会执行。无论try中是否字符间距怎么加宽存在异常,还是正常的情况,finally一定会执行,区别在于基本数据类型与对象属性以及返回的值是不是我们所期字符望的,对于属性,由于kotlin和javajava值传递可以很好解释,即使finally中不包含return,依然会覆盖了。而基本数据类型的值返回情况,字节码信息中也很清晰,有兴起的可java是什么意思以编译出来看看就一目了然了。以前仅仅知道,或者是记住finally代码一定会执行,通过编译出来,就可以很清晰的知道jvm到底是怎样保证这个机制的。

六、结论
  • try、catch、finally均有return字段时,对于基本数据类型或是对象的属性,无论是异常情况还是正常的情况,finally中的代码一定会被执行,并且此时的返回值不是try或者catch中计算的期望值,而是finally最终修改的值。

  • try、catchreturn字段而finally中没字符型变量有时,java环境变量配置对于正常的情况下并且是基测试手机是否被监控本数字符常量据类型,返回值是try中计算的期望值,而对于对象的属性依然会被finally所覆盖。(另外虽然基本数据类型在finally中没有被返回,但其实值已经被修改,try中返回Kotlin的值是其kotlin和java首次计算得到的结果的保存值)。

  • try、catchreturn字段而finally中没有时,对于异常的情况下并且是基本数据类型,返回值是catch中计算的期望值,java面试题而对于对象的属性依然会被final测试用例ly字节码是什么意思所覆盖。(另外虽然基本数据类型在finally中没有被返回,但其实值已经被修改,catch中返回的值是测试英文其首次计算得到的结果Kotlin的保存值)。

  • finally一定会被执行,这是从编字节码是什么意思译信息中得出的,这就要求在平字符间距加宽2磅怎么设置时编码的时候测试抑郁症要特别注意,并且最好是不要在其测试抑郁症内部执行字节码return操作,一般场景下,接触的比较多的就是对资源的释放,比如IO流的关闭操作等。