zoukankan      html  css  js  c++  java
  • finally 语句块是否一定会被执行?

    结论

    结论:不一定,存在两种可能的情况。第一种,调用了 System.exit,第二种,finally 语句位于一个线程中,但是这个线程随着主线程的终结而终结了。代码请看 example1.另外值得注意的是,即使在 try 中 return 了,还是会执行后面的 finally。

    代码:

    输出:

    原理

    那 try, catch, finally 是如何实现的呢?下面我们用反汇编看看。

    反汇编命令 javap -c -p Example1.class,完整的反汇编代码放到了最后。

    异常表

    我们可以看到在 test 函数的最后,有一个异常表。表头有四列,from to target type。一共有三行。第一行是 try 语句块中,如果发生 Exception 这个异常,那么将跳转到第 48 行执行。第二,第三行,跳转到 finally 中去执行。

    那这个 any 是什么呢?如果还没有看反汇编的代码,你可能会觉得这就是 finally 的实现原理了,执行完 try/catch 块之后就跳转到 finally 语句块去执行。可是,看看反汇编的代码,就会发现这个函数中,有三个 finally 语句块!在 try 后面有一个,在 catch 后面还有两个。所以,这里我猜是除了 catch 之外的其他异常,如果在 try 和 catch 中发生了没有捕获的异常,那么就去执行 finally 语句块。

    原理

    通过分析后面的反汇编代码,我们可以看出来:

    1. finally 基本都是要执行的,除非暴力的 System.exit 或者线程提前终结了。
    2. catch 的实现方法是异常表。多个 try...catch,嵌套的 try...catch 共用一个异常表,不同方法不共用异常表。这个你可以检验一下。
    3. try 即使 return,finally 都还执行的原因,是 java 在编译的时候,在 try 语句块的 return 之前插入代码。而且,return 的内容可以被 finally 的 return 覆盖。
    4. try, catch 没有捕获的异常,会在 finally 中抛出,athrow 指令。所以不要在 finally 中 return,否则这些没有捕获的异常将不会被抛出。

    完整的反汇编代码。

    Compiled from "Example1.java"
    
    public class example.Example1 {
      public example.Example1();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: invokestatic  #2                  // Method test:()Lexample/Example1$Apple;
           3: astore_1
           4: aload_1
           5: invokevirtual #3                  // Method example/Example1$Apple.show:()V
           8: return
    
      private static example.Example1$Apple test();
        Code:
           0: iconst_0
           1: istore_0
           2: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
           5: ldc           #5                  // String ִ���� try ����
           7: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          10: iconst_1
          11: istore_0
          12: iconst_2
          13: newarray       int
          15: astore_1
          16: aload_1
          17: iconst_5
          18: iconst_0
          19: iastore
          20: new           #7                  // class example/Example1$Apple
          23: dup
          24: iload_0
          25: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
          28: astore_2
          29: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
          32: ldc           #9                  // String ִ���� finally ����
          34: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          37: iconst_3
          38: istore_0
          39: new           #7                  // class example/Example1$Apple
          42: dup
          43: iload_0
          44: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
          47: areturn
          48: astore_1
          49: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
          52: ldc           #11                 // String ִ���� catch ����
          54: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          57: iconst_2
          58: istore_0
          59: new           #7                  // class example/Example1$Apple
          62: dup
          63: iload_0
          64: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
          67: astore_2
          68: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
          71: ldc           #9                  // String ִ���� finally ����
          73: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          76: iconst_3
          77: istore_0
          78: new           #7                  // class example/Example1$Apple
          81: dup
          82: iload_0
          83: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
          86: areturn
          87: astore_3
          88: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
          91: ldc           #9                  // String ִ���� finally ����
          93: invokevirtual #6                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          96: iconst_3
          97: istore_0
          98: new           #7                  // class example/Example1$Apple
         101: dup
         102: iload_0
         103: invokespecial #8                  // Method example/Example1$Apple."<init>":(I)V
         106: areturn
        Exception table:
           from    to  target type
               2    29    48   Class java/lang/Exception
               2    29    87   any
              48    68    87   any
    }
    
  • 相关阅读:
    java垃圾回收机制
    浮点数比较/运算BigDecimal
    java8新特性_::双冒号
    java的lambda表达式
    【转】DelphiXE10.2.3——跨平台生成验证码图片
    ide fix pack for delph 10.2.3发布了
    使用ALVideoPlayerSurface制作视频播放器
    kbmMWLog同时输出日志到多个日志管理器
    kbmMWLog输出日志到控制台或指定Grid
    推荐内置android控件的开源项目alcinoe
  • 原文地址:https://www.cnblogs.com/zzk0/p/14385945.html
Copyright © 2011-2022 走看看