finally 块总是在 Java 中执行吗?

Does a finally block always get executed in Java?

提问人:jonny five 提问时间:9/16/2008 最后编辑:Anshul Sharmajonny five 更新时间:7/5/2023 访问量:606241

问:

考虑到这段代码,我能否绝对确定该块始终执行,无论是什么?finallysomething()

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}
java 错误处理 返回 try-catch-finally

评论

61赞 Boann 9/23/2013
并非总是如此
3赞 Binoy Babu 12/14/2014
有效的 java 不然 informit.com/articles/article.aspx?p=1216151&seqNum=7
36赞 jaco0646 7/13/2016
@BinoyBabu,终结器 != ;finalizer == 方法。finallyfinalize()
4赞 MC Emperor 1/20/2017
@Boann 没错,“并非总是”确实如此。但是,您永远不能使用“保证”或“始终”这两个词。
2赞 Imperishable Night 10/27/2018
@Boann 我会这样说:执行流总是在逃脱 try-finally 结构之前最终通过。如果它在内部死了,那么我对此没问题,因为 final 的主要目的是确保代码的其他部分不会搞砸。

答:

3002赞 jodonnell 9/16/2008 #1

是的,将在执行 or 代码块后调用。finallytrycatch

唯一不会被调用的时间是:finally

  1. 如果调用System.exit()
  2. 如果调用Runtime.getRuntime().halt(exitStatus)
  3. 如果 JVM 首先崩溃
  4. 如果 JVM 到达 or 块中的无限循环(或其他一些不可中断、非终止的语句)trycatch
  5. 如果操作系统强行终止 JVM 进程;例如,在 UNIX 上kill -9 <pid>
  6. 如果主机系统死机;例如,电源故障、硬件错误、操作系统崩溃等
  7. 如果该块将由守护进程线程执行,并且所有其他非守护进程线程在调用之前退出finallyfinally

评论

47赞 Piotr Findeisen 3/31/2011
实际上并不一定阻止块被执行。thread.stop()finally
215赞 Andrzej Doyle 9/16/2011
不如我们说块将在块之后调用,在控制权传递给以下语句之前。这与涉及无限循环的 try 块一致,因此 finally 块从未真正被调用。finallytry
9赞 ruhungry 3/23/2014
还有另一种情况,当我们使用嵌套的 try-catch-finally 块时
16赞 avmohan 1/5/2017
@BinoyBabu - 这是关于终结者,而不是最终阻止
8赞 SusanW 6/6/2017
@AmrishPandey Oracle 页面根本没有提到守护进程。另一个(博客)页面讨论了 JVM 终止,但未能继续显示与非守护程序线程的任何区别。现实情况是:在 System.exit 完成(包括关闭钩子)或其他终止时,无论是否守护进程,所有线程都会死在它们所在的位置:无论哪种方式都没有最终执行。博主指出这是不正确的,他们认为这是一个差异......自己试试吧。
21赞 shyam 9/16/2008 #2

finally除非有异常程序终止(如调用),否则始终执行。所以,你的意志会被打印出来。System. exit(0)System.out

10赞 Mendelt 9/16/2008 #3

是的,它会被调用。这就是拥有最终关键字的全部意义所在。如果跳出 try/catch 块可以跳过 finally 块,这与将 System.out.println 放在 try/catch 之外是一样的。

623赞 Kevin 9/16/2008 #4

示例代码:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("something is printed");
    }
}

输出:

something is printed. 
0

评论

22赞 Alexander Pacha 10/31/2013
仅供参考:在 C# 中,除了不允许将 -子句中的语句替换为 (Compiler-Error) 之外,行为是相同的。finallyreturn 2;
15赞 WoodenKitty 12/4/2013
这是一个需要注意的重要细节: stackoverflow.com/a/20363941/2684342
24赞 Zyl 4/16/2015
您甚至可以在 finally 块本身中添加一个 return 语句,然后该语句将覆盖之前的返回值。这也神奇地丢弃了未经处理的异常。此时,应考虑重构代码。
10赞 Trimtab 6/21/2016
这并不能真正证明最终胜过回报。返回值是从调用方代码打印的。似乎并不能证明什么。
23赞 Stephen C 8/20/2017
对不起,这是一个演示而不是证明。只有当你能证明这个例子在所有 Java 平台上总是以这种方式行事,并且类似的例子也总是以这种方式行事时,它才是一个证明。
7赞 Scott Dorman 9/16/2008 #5

实际上,在任何语言中都是如此......finally 将始终在 return 语句之前执行,无论该返回位于方法体中的哪个位置。如果不是这样,最后的块就没有太大意义了。

18赞 user9189 9/16/2008 #6

除非存在异常程序终止,否则始终执行 finally 块,无论是由于 JVM 崩溃还是由于调用 .System.exit(0)

最重要的是,从 finally 块中返回的任何值都将覆盖在执行 finally 块之前返回的值,因此在使用 try finally 时要小心检查所有退出点。

424赞 MooBob42 9/16/2008 #7

此外,尽管这是不好的做法,但如果 finally 块中有 return 语句,它将胜过常规块的任何其他返回。也就是说,以下块将返回 false:

try { return true; } finally { return false; }

从最终块抛出异常也是如此。

评论

106赞 John Meagher 9/16/2008
这是一个非常糟糕的做法。请参阅 stackoverflow.com/questions/48088/...,了解有关它为何不好的更多信息。
23赞 neu242 10/22/2008
同意。finally{} 中的返回将忽略 try{} 中抛出的任何异常。可怕!
10赞 corsiKa 7/13/2011
@dominicbri7 为什么你认为这是一种更好的做法?当函数/方法无效时,为什么会有所不同?
8赞 dominicbri7 7/13/2011
出于同样的原因,我从不在我的C++代码中使用goto。我认为多个返回使它更难阅读和调试(当然,在非常简单的情况下,它不适用)。我想这只是个人偏好,最终您可以使用任何一种方法实现相同的目标
18赞 iHearGeoff 2/23/2013
当发生某种特殊情况时,我倾向于使用一些退货。比如如果(有理由不继续)返回;
18赞 James A. N. Stauffer 9/16/2008 #8

此外,最终返回将抛弃任何例外。http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

42赞 Garth Gilmour 9/16/2008 #9

一个合乎逻辑的思考方式是:

  1. 无论 try 块中发生什么,都必须执行放置在 finally 块中的代码
  2. 因此,如果 try 块中的代码尝试返回值或抛出异常,则该项将被放置在“搁置”上,直到最后一个块可以执行
  3. 因为 finally 块中的代码(根据定义)具有很高的优先级,所以它可以返回或抛出它喜欢的任何内容。在这种情况下,任何留在“架子上”的东西都会被丢弃。
  4. 唯一的例外是,如果 VM 在 try 块期间完全关闭,例如通过“System.exit”

评论

10赞 matias 5/27/2010
这只是“一种合乎逻辑的思考方式”,还是最终块真的打算按照规范工作?在这里,指向 Sun 资源的链接将非常有趣。
7赞 Alex Miller 10/1/2008 #10

除了最终替换 try 块中的返回时关于返回的要点之外,异常也是如此。抛出异常的 finally 块将替换从 try 块中抛出的返回或异常。

130赞 vibhash 11/18/2008 #11

我尝试了上面的例子,略有修改-

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

上面的代码输出:

终于胜过了回归。
阿拉伯数字

这是因为 when is executed 的值为 2。在此之后,执行块,其中 12 被分配给,然后执行 out。return i;ifinallyiSystem.out

执行块后,块返回 2,而不是返回 12,因为此 return 语句不会再次执行。finallytry

如果你在 Eclipse 中调试这段代码,那么你会感觉到在执行 block 之后,block 的语句会再次执行。但事实并非如此。它只返回值 2。System.outfinallyreturntry

评论

12赞 HopefullyHelpful 9/8/2016
这个例子很棒,它添加了一些在几十个最终相关线程中没有提到的东西。我认为几乎没有任何开发人员会知道这一点。
5赞 Yamcha 9/10/2016
如果不是基元,而是 Integer 对象。i
0赞 the-dumb-programmer 11/16/2016
我很难理解这个案子。docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.17 说,“带有 Expression 的 return 语句试图将控制权转移给包含它的方法或 lambda 主体的调用者......如果表达式的计算正常完成,则生成值 V..”我可以从这句话中猜到的是 - 似乎返回在计算值 V 后不会再次计算表达式,这就是为什么更改 i 不会影响返回值的原因,纠正我。
0赞 the-dumb-programmer 11/16/2016
但是我找不到任何关于这一点的证据,哪里提到 return 不会再次计算表达式。
1赞 user85421 5/18/2017
@meexplorer有点晚了,但在 JLS 14.20.2 中对此进行了解释。try-finally 和 try-catch-finally 的执行 - 措辞有点复杂,14.17。还必须阅读 return 语句
12赞 Motti 5/13/2010 #12

最后总是运行,这就是重点,仅仅因为它在返回后出现在代码中并不意味着这就是它的实现方式。Java 运行时有责任在退出块时运行此代码。try

例如,如果您有以下情况:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

运行时将生成如下内容:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

如果抛出未捕获的异常,则该块将运行,并且异常将继续传播。finally

10赞 Jay Riggs 5/13/2010 #13

因为除非您调用(或线程崩溃),否则将始终调用 finally 块。System.exit()

52赞 Chris Cooper 5/13/2010 #14

这就是最终块的整个想法。它可以让你确保你做了清理,否则可能会因为你返回而被跳过,当然,还有其他事情。

无论 try 块中发生什么情况,最后都会被调用(除非您调用或 Java 虚拟机因其他原因踢出)。System.exit(int)

评论

0赞 Gangnus 5/8/2019
这是一个非常薄弱的答案。stackoverflow.com/a/65049/715269
174赞 Eyal Schneider 5/13/2010 #15

除了其他响应之外,需要指出的是,“finally”有权通过 try 覆盖任何异常/返回值。catch 块。例如,以下代码返回 12:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

同样,以下方法不会引发异常:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

虽然以下方法确实抛出它:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}

评论

69赞 Dimitris Andreou 5/13/2010
应该注意的是,中间情况恰恰是为什么在 finally 块中有一个 return 语句是绝对可怕的原因(它可以隐藏任何 Throwable)。
3赞 RecursiveExceptionException 2/8/2019
想要一个被压抑的人?;)OutOfMemoryError
0赞 Maarten Bodewes 12/23/2019
我测试了它,它确实抑制了这样的错误(哎呀!当我编译它时,它还会生成警告(耶!你可以通过定义一个返回变量,然后在块之后使用来解决它,尽管这当然假设你抑制了其他一些异常,因为否则代码就没有意义了。return retValfinally
10赞 Wasim 5/25/2010 #16

这是因为您将 i 的值指定为 12,但没有将 i 的值返回给函数。正确的代码如下:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
264赞 polygenelubricants 5/25/2010 #17

以下是 Java 语言规范中的官方用语。

14.20.2. try-finally 和 try-catch-finally 的执行

带有 finally 块的 try 语句通过首先执行 try 块来执行。然后有一个选择:

  • 如果区块的执行正常完成,[...]try
  • 如果由于值 V 的 a 而突然完成块的执行,[...]trythrow
  • 如果由于任何其他原因 R 而突然完成 try 块的执行,则执行 final 块。然后有一个选择:
    • 如果 finally 块正常完成,则语句因原因 R 而突然完成。try
    • 如果块由于原因 S 而突然完成,则语句因原因 S 而突然完成(并且原因 R 被丢弃)。finallytry

实际上,规范对此进行了明确说明:return

JLS 14.17 return 语句

ReturnStatement:
     return Expression(opt) ;

尝试将控制权转移给包含它的方法或构造函数的调用方的语句。returnExpression

尝试将控制权转移给包含该控制权的方法的调用方的语句;的值成为方法调用的值。returnExpressionExpression

前面的描述说的是“尝试转移控制权”,而不仅仅是“转移控制权”,因为如果方法或构造函数中有任何语句,其块包含该语句,那么这些语句的任何子句都将按从最内层到最外层的顺序执行,然后再将控制权传递给方法或构造函数的调用者。条款的突然完成可能会中断由语句发起的控制权转移。trytryreturnfinallytryfinallyreturn

19赞 Rajendra Jadi 7/14/2013 #18

不,并非总是如此,在块阻止执行之前,会出现一种异常情况。System.exit(0);finallyfinally

      class A {
        public static void main(String args[]) {
            DataInputStream cin = new DataInputStream(System.in);

            try {
                int i = Integer.parseInt(cin.readLine());
            } catch (ArithmeticException e) {
            } catch (Exception e) {
               System.exit(0); // Program terminates before executing the finally block
            } finally {
                System.out.println("Won't be executed");
                System.out.println("No error");
            }
        }
    }

评论

0赞 Franz D. 9/11/2018
这就是你真的不应该调用 System.exit() 的原因之一......
9赞 Karthikeyan 8/16/2013 #19

是的,它会的。无论 try 或 catch 块中发生什么,除非 System.exit() 被调用或 JVM 崩溃。如果区块中有任何 return 语句,则 final 将在该 return 语句之前执行。

133赞 WoodenKitty 12/4/2013 #20

以下是凯文回答的详细说明。重要的是要知道要返回的表达式是在 之前计算的,即使它返回的时间在之后。finally

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int printX() {
    System.out.println("X");
    return 0;
}

public static int test() {
    try {
        return printX();
    }
    finally {
        System.out.println("finally trumps return... sort of");
        return 42;
    }
}

输出:

X
finally trumps return... sort of
42

评论

10赞 Aminadav Glickshtein 7/6/2018
重要的是要知道。
0赞 Albert 6/26/2019
很高兴知道,也很有意义。似乎实际返回 return 的值是后面的内容。计算返回值(此处)仍然在它之前。finallyprintX()
2赞 Pacerier 5/10/2020
不。上面的代码应替换为System.out.println("finally trumps return... sort of");System.out.print("finally trumps return in try"); return 42;
0赞 Christopher Schultz 6/10/2022
这个答案是完全不言而喻的 IMO,因为不会返回一些神奇的延续,只有在调用者打印它或其他什么时才会被评估。 在发生之前被调用,而不管任何 / 或其他任何事情。returnprintX()returntrycatch
8赞 abhig 1/15/2014 #21

是的,它会的。 唯一不会的情况是JVM退出或崩溃

10赞 bikz05 10/14/2014 #22

简明扼要地,在官方的 Java 文档(点击这里)中,它写道——

如果 JVM 在执行 try 或 catch 代码时退出,则 finally 块可能无法执行。同样,如果线程执行 try 或 catch 代码被中断或终止,最后的块可能会 即使整个应用程序继续,也不会执行。

8赞 Gautam Viradiya 12/2/2014 #23

是的,最后块总是被执行。大多数开发人员使用这个块来关闭数据库连接、resultset 对象、语句对象,并且还使用 into java 休眠来回滚事务。

8赞 Utkarsh Bhatt 12/18/2014 #24

finally将执行,这是肯定的。

finally在以下情况下不会执行:

案例 1 :

当您执行 .System.exit()

案例 2 :

当您的 JVM/线程崩溃时。

案例 3 :

当您的执行在两者之间手动停止时。

11赞 Anonymous Coward 12/12/2015 #25

并非总是如此

Java 语言规范描述了 -- 和 - 块在 14.20.2
中的工作方式,它没有在任何地方指定始终执行块。 但是,对于 -- 和 - 块完成的所有情况,它确实指定了在完成之前必须执行。
trycatchfinallytrycatchfinallytrycatchfinallytryfinallyfinally

try {
  CODE inside the try block
}
finally {
  FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).

JLS 不保证 FINCODE 之后执行。 JLS 保证如果执行 CODE 和 NEXT,则 FIN 将始终在 CODE 之后和 NEXT 之前执行。

为什么 JLS 不能保证区块总是在区块之后执行?因为这是不可能的。JVM 不太可能,但有可能在完成块后但在块执行之前被中止(终止、崩溃、关机)。JLS无法避免这种情况。finallytrytryfinally

因此,任何软件的正常行为都依赖于块的执行,总是在块完成后执行。finallytry

return块中的说明与此问题无关。如果执行到达代码之后 -- 则保证该块在块内有或没有指令之前就已经执行了。trytrycatchfinallyfinallyreturntry

评论

0赞 filpa 6/9/2021
我很抱歉评论这样一个古老的答案,但我认为说得不太对。 块通常用于资源清理以防止泄漏。不然你会怎么做?同样,您也不能(或不应该...)捕获 s,因为(通常)没有合理的方法来处理它们。any software which for their proper behaviour depends on finally blocks always being executed after their try blocks complete are bugged.finallyError
0赞 Anonymous Coward 6/21/2021
@user991710 如果 finally 块中的清理是关于关闭打开的文件,那么不执行 finally 块不是问题,操作系统会在程序终止时关闭它。如果清理是删除有问题的文件,则当程序在最终中止之前,操作系统不会执行此操作。如果系统的另一部分依赖于 java 程序总是执行此类删除操作,那么整个系统,尤其是 java 程序都会被窃听。你不能指望最终总是执行。如果 NEXT 已执行,则只能依赖最终已执行的保证
0赞 filpa 6/21/2021
有趣的是,尽管据我所知,它迫使你设计的某些部分。扩展您的删除示例:您是否正在运行一种负责删除(清理)文件的“收割者”任务?我承认,鉴于您的解释,使用可能会(如果有足够的时间,可能会)导致错误,但是额外的开发(和测试)时间是否值得在稳定性方面可能不明显的改进?更一般地说:特定设计中应采取的谨慎程度是否取决于所讨论的子系统?毕竟,时间是一种宝贵的资源。:)finally
1赞 Anonymous Coward 6/23/2021
@user991710 最后使用没有错。你只需要知道它做什么,不做什么。对于删除文件的特殊情况,我实际上会在 finally 块中执行此操作。但是要知道这样做并不能保证(即使 try 块的最后一行完成执行),我会采取预防措施来处理这种情况。因此,删除以前的剩余文件作为执行程序的第一步,如果这是一个服务风格的程序,它将自动重新运行。如果在这种情况下系统故障无关紧要,那么当然,不要打扰
8赞 dkb 3/21/2016 #26

我试过了这个, 它是单线程的。

public static void main(String args[]) throws Exception {
    Object obj = new Object();
    try {
        synchronized (obj) {
            obj.wait();
            System.out.println("after wait()");
        }
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

将永远处于状态,因此最终永远不会被召唤mainThreadwait

所以控制台输出不会 : after 或printStringwait()finally

与@Stephen C 一致,上面的例子是这里提到的第 3 种情况之一:

在下面的代码中添加更多这样的无限循环可能性:

// import java.util.concurrent.Semaphore;

public static void main(String[] args) {
    try {
        // Thread.sleep(Long.MAX_VALUE);
        // Thread.currentThread().join();
        // new Semaphore(0).acquire();
        // while (true){}
        System.out.println("after sleep join semaphore exit infinite while loop");
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

案例 2:如果 JVM 首先崩溃

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public static void main(String args[]) {
    try {
        unsafeMethod();
        //Runtime.getRuntime().halt(123);
        System.out.println("After Jvm Crash!");
    } catch (Exception e) {
    } finally {
        System.out.println("finally");
    }
}

private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    unsafe.putAddress(0, 0);
}

参考:你如何使JVM崩溃?

情况 6:如果 block 将由 daemon 执行,并且调用了 before 所有其他非守护进程 exit。finallyThreadThreadsfinally

public static void main(String args[]) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                printThreads("Daemon Thread printing");
                // just to ensure this thread will live longer than main thread
                Thread.sleep(10000);
            } catch (Exception e) {
            } finally {
                System.out.println("finally");
            }
        }
    };
    Thread daemonThread = new Thread(runnable);
    daemonThread.setDaemon(Boolean.TRUE);
    daemonThread.setName("My Daemon Thread");
    daemonThread.start();
    printThreads("main Thread Printing");
}

private static synchronized void printThreads(String str) {
    System.out.println(str);
    int threadCount = 0;
    Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
    for (Thread t : threadSet) {
        if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
            System.out.println("Thread :" + t + ":" + "state:" + t.getState());
            ++threadCount;
        }
    }
    System.out.println("Thread count started by Main thread:" + threadCount);
    System.out.println("-------------------------------------------------");
}

输出:这不会打印“finally”,这意味着“守护进程线程”中的“最后块”未执行

main Thread Printing  
Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED  
Thread :Thread[main,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE   
Thread count started by Main thread:3  
-------------------------------------------------  
Daemon Thread printing  
Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE  
Thread count started by Main thread:2  
-------------------------------------------------  

Process finished with exit code 0

评论

4赞 Stephen C 8/20/2017
查看接受的答案。这只是“无限循环”的一个边缘情况。
10赞 Meet Vora 8/13/2016 #27

答案很简单:是的

输入:

try{
    int divideByZeroException = 5 / 0;
} catch (Exception e) {
    System.out.println("catch");
    return;    // also tried with break; in switch-case, got same output
} finally {
    System.out.println("finally");
}

输出:

catch
finally

评论

2赞 Christophe Roussy 12/14/2017
答案很简单:不。
1赞 Meet Vora 12/14/2017
@ChristopheRoussy如何?你能解释一下吗?
1赞 Christophe Roussy 12/14/2017
阅读公认的答案,原来的问题是关于“它会一直执行吗”,它不会总是执行。在你的情况下,它会,但这并不能回答最初的问题,甚至可能误导初学者。
0赞 Meet Vora 12/15/2017
那么在哪种情况下它不会被执行?
0赞 Christophe Roussy 12/18/2017
在其他答案中提到的所有情况下,请参阅接受的答案和 1000+ 赞成票。
9赞 Pradeep Kumaresan 4/10/2018 #28

补充@vibhash的答案,因为没有其他答案可以解释在可变对象的情况下会发生什么,如下所示。

public static void main(String[] args) {
    System.out.println(test().toString());
}

public static StringBuffer test() {
    StringBuffer s = new StringBuffer();
    try {
        s.append("sb");
        return s;
    } finally {
        s.append("updated ");
    }
}

将输出

sbupdated 

评论

0赞 sam 4/30/2018
从 Java 1.8.162 开始,这不是输出。
8赞 sam 4/30/2018 #29

请考虑以下程序:

public class SomeTest {

    private static StringBuilder sb = new StringBuilder();

    public static void main(String args[]) {

        System.out.println(someString());
        System.out.println("---AGAIN---");
        System.out.println(someString());
        System.out.println("---PRINT THE RESULT---");
        System.out.println(sb.toString());
    }

    private static String someString() {

        try {
            sb.append("-abc-");
            return sb.toString();

        } finally {
            sb.append("xyz");
        }
    }
}

从 Java 1.8.162 开始,上面的代码块给出了以下输出:

-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz

这意味着使用释放对象是一种很好的做法,如以下代码所示:finally

private static String someString() {

    StringBuilder sb = new StringBuilder();

    try {
        sb.append("abc");
        return sb.toString();

    } finally {
        sb = null; // Just an example, but you can close streams or DB connections this way.
    }
}

评论

0赞 Ori Marko 9/5/2018
最后不应该进去吗?sb.setLength(0)
0赞 sam 9/6/2018
sb.setLength(0) 将清空 StringBuffer 中的数据。因此,sb = null 将取消对象与引用的关联。
0赞 fresko 2/13/2019
“xyz”不应该在输出中打印两次吗?既然函数被调用了两次,为什么“最后”只有一次?
3赞 Roc Boronat 2/16/2019
这不是一个好的做法。最后的块只是添加了不需要的代码。我知道您的意思是块是释放数据库连接或类似资源的好地方,但请记住,您的示例可能会使新手感到困惑。sb = null;finally
1赞 fresko 2/19/2019
@Samim 谢谢,我添加了这些行,现在更清楚了。事实上,输出与你的论文:p我还补充了您的答案,但编辑必须被版主或类似的人接受。否则,您可以添加它们System.out.println("---AGAIN2---");System.out.println(sb);
10赞 hellzone 1/27/2020 #30

finally块总是在返回 的(计算)值之前执行。x

System.out.println("x value from foo() = " + foo());

...

int foo() {
  int x = 2;
  try {
    return x++;
  } finally {
    System.out.println("x value in finally = " + x);
  }
}

输出:

最后 x 值 = 3
x foo() 的值 = 2

评论

0赞 President James K. Polk 2/5/2020
很好的说明性例子,+1。