2584

考虑到这段代码,我是否可以绝对确定finally块始终执行,无论something()是什么?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}
4

51 回答 51

2910

是的,finally将在trycatch代码块执行后调用。

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

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

示例代码:

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
于 2008-09-15T17:59:52.460 回答
413

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

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

从 finally 块中抛出异常也是如此。

于 2008-09-15T18:19:53.507 回答
262

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

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

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

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

的规范return实际上明确了这一点:

JLS 14.17 返回声明

ReturnStatement:
     return Expression(opt) ;

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

试图将控制权转移给包含它的方法的调用者的语句return;的值成为方法调用的值。Expression Expression

前面的描述说“尝试转移控制”而不仅仅是“转移控制try”,因为如果方法或构造函数中有任何语句的try块包含该return语句,那么finally这些语句的任何子句都try将按从内到外的顺序执行,在将控制权转移到方法或构造函数的调用者之前。一个子句的突然完成finally可能会中断由return语句启动的控制转移。

于 2010-05-25T06:50:16.820 回答
171

除了其他响应之外,重要的是要指出“终于”有权覆盖 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();
    }
}
于 2010-05-13T07:11:59.567 回答
127

我尝试了上面的例子,稍作修改-

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

上面的代码输出:

终于胜过回归。
2

这是因为 when return i;is executedi的值为 2。在此之后finally执行块,其中分配了 12 i,然后System.out执行 out。

执行完finally块后,try块返回 2,而不是返回 12,因为这个 return 语句不再执行。

如果您将在 Eclipse 中调试此代码,那么您会感觉到在执行块之后再次执行System.outfinallyreturn语句try。但这种情况并非如此。它只是返回值 2。

于 2008-11-17T16:25:36.027 回答
126

这是凯文答案的详细说明。重要的是要知道要返回的表达式是在之前计算的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");
    }
}

输出:

X
finally trumps return... sort of
0
于 2013-12-03T23:36:13.040 回答
52

这就是 finally 块的全部想法。它可以让你确保你做的清理工作可能会因为你返回而被跳过,当然,除其他外。

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

于 2010-05-13T06:19:17.580 回答
42

考虑这个问题的一个合乎逻辑的方法是:

  1. 放置在 finally 块中的代码必须在 try 块中发生的任何情况下执行
  2. 因此,如果 try 块中的代码尝试返回值或抛出异常,则该项目将被放在“货架上”,直到 finally 块可以执行
  3. 因为 finally 块中的代码(根据定义)具有高优先级,它可以返回或抛出任何它喜欢的东西。在这种情况下,任何留在“架子上”的东西都会被丢弃。
  4. 唯一的例外是如果虚拟机在尝试块期间完全关闭,例如通过“System.exit”
于 2008-09-15T19:26:44.797 回答
21

finally 总是被执行,除非有异常的程序终止(比如调用 System.exit(0)..)。所以,你的系统输出将被打印出来

于 2008-09-15T17:46:18.343 回答
19

不,并非总是一种例外情况是// System.exit(0); 在 finally 块阻止 finally 被执行之前。

  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 finally block
        }finally{
            System.out.println("Won't be executed");
            System.out.println("No error");
        }
    }
}
于 2013-07-13T23:02:23.970 回答
18

finally 块总是被执行,除非程序异常终止,要么是由于 JVM 崩溃,要么是由于调用System.exit(0).

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

于 2008-09-15T18:11:55.660 回答
18

finally 中的 return 也会抛出任何异常。 http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

于 2008-09-15T19:26:15.717 回答
12

finally 总是 run 这就是重点,仅仅因为它出现在 return 之后的代码中并不意味着它就是这样实现的。Java 运行时有责任在退出try块时运行此代码。

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

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

运行时将生成如下内容:

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

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

于 2010-05-13T06:18:23.697 回答
10

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

于 2008-09-15T17:46:40.043 回答
10

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

于 2010-05-13T06:19:17.147 回答
10

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

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
于 2010-05-25T06:36:29.320 回答
10

简而言之,在官方 Java 文档(单击此处)中,写到 -

如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。

于 2014-10-13T21:51:50.630 回答
10

不总是

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

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 不保证FIN在CODE之后执行。JLS 保证如果CODENEXT被执行,那么FIN将始终在CODE之后和NEXT之前执行。

为什么 JLS 不保证finally块总是在try块之后执行?因为这是不可能的。try在完成块之后但在执行块之前,JVM 不太可能但可能会中止(杀死、崩溃、关闭电源)finally。JLS 无法避免这种情况。

因此,任何在其块完成后总是依赖于finally块的正确行为的软件都会被try窃听。

return块中的指令try与此问题无关。如果执行到达try- catch-之后的代码finally,则保证该finally块之前已经执行过,无论块return内是否有指令try

于 2015-12-12T14:30:53.560 回答
10

答案很简单YES

输入:

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
于 2016-08-13T07:00:38.443 回答
10

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

输出:

finally 中的 x 值 = 3
x 来自 foo() 的值 = 2

于 2020-01-27T13:24:21.903 回答
9

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

于 2013-08-16T12:00:20.937 回答
8

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

于 2014-01-14T22:29:17.323 回答
8

是的,finally 块总是执行。大多数开发人员使用此块来关闭数据库连接、结果集对象、语句对象,并使用 java hibernate 来回滚事务。

于 2014-12-02T12:30:14.930 回答
8

finally将执行,这是肯定的。

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

情况1 :

当你正在执行System.exit().

案例2:

当您的 JVM / 线程崩溃时。

案例3:

当您手动停止执行时。

于 2014-12-18T06:36:56.457 回答
8

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

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

将永远main Thread处于wait状态,因此finally永远不会被调用

所以控制台输出不会print String:在wait()或之后finally

同意@Stephen C,上面的例子是这里提到的第三种情况之一:

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

// 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:如果finally块将由守护进程执行,并且调用之前的Thread所有其他非守护进程Threads退出。finally

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”,这意味着“daemon thread”中的“Finally block”没有执行

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
于 2016-03-20T16:20:42.763 回答
8

添加到@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 
于 2018-04-10T11:33:34.993 回答
8

考虑以下程序:

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.
    }
}
于 2018-04-30T08:36:45.770 回答
7

这实际上在任何语言中都是正确的……finally 总是在 return 语句之前执行,无论 return 在方法体中的什么位置。如果不是这样,finally 块就没有多大意义。

于 2008-09-15T18:03:05.637 回答
7

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

于 2008-10-01T15:15:44.153 回答
7

我对不同论坛上提供的所有答案感到非常困惑,并决定最终编码并查看。输出是:

即使在 try 和 catch 块中有 return,finally 也会被执行。

try {  
  System.out.println("try"); 
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} catch (Exception e) {   
  System.out.println("catch");
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} finally {  
   System.out.println("Print me FINALLY");
}

输出

尝试

最后打印我

  1. 如果在上面的代码中,return 被替换为System.exit(0)try 和 catch 块,并且在它之前发生异常,无论出于何种原因。
于 2015-05-13T11:11:01.483 回答
7
  1. finally 块总是被执行。除非并且直到 System.exit()语句在那里存在(finally 块中的第一条语句)。
  2. 如果system.exit()是第一个语句,那么 finally 块将不会被执行并且控制来自 finally 块。每当 System.exit() 语句进入 finally 块,直到该语句最终块执行,当 System.exit() 出现时,控制力完全从 finally 块中出来。
于 2017-05-20T12:16:09.667 回答
6

如果不处理异常,在终止程序之前,JVM 会执行 finally 块。只有当程序的正常执行失败意味着由于以下原因终止程序时,它才会执行。

  1. 通过导致导致进程中止的致命错误。

  2. 由于内存损坏而终止程序。

  3. 通过调用 System.exit()

  4. 如果程序进入无限循环。

于 2017-06-08T12:41:40.633 回答
6

是的,因为没有控制语句可以阻止finally执行。

这是一个参考示例,其中将执行所有代码块:

| x | Current result | Code 
|---|----------------|------ - - -
|   |                |     
|   |                | public static int finallyTest() {
| 3 |                |     int x = 3;
|   |                |     try {
|   |                |        try {
| 4 |                |             x++;
| 4 | return 4       |             return x;
|   |                |         } finally {
| 3 |                |             x--;
| 3 | throw          |             throw new RuntimeException("Ahh!");
|   |                |         }
|   |                |     } catch (RuntimeException e) {
| 4 | return 4       |         return ++x;
|   |                |     } finally {
| 3 |                |         x--;
|   |                |     }
|   |                | }
|   |                |
|---|----------------|------ - - -
|   | Result: 4      |

在下面的变体中,return x;将被跳过。结果仍然是4

public static int finallyTest() {
    int x = 3;
    try {
        try {
            x++;
            if (true) throw new RuntimeException("Ahh!");
            return x; // skipped
        } finally {
            x--;
        }
    } catch (RuntimeException e) {
        return ++x;
    } finally {
        x--;
    }
}

当然,参考文献会跟踪它们的状态。此示例返回一个引用value = 4

static class IntRef { public int value; }
public static IntRef finallyTest() {
    IntRef x = new IntRef();
    x.value = 3;
    try {
        return x;
    } finally {
        x.value++; // will be tracked even after return
    }
}
于 2017-12-16T15:36:36.123 回答
6

try- catch-finally是使用异常处理案例的关键词。
正常解释

try {
     //code statements
     //exception thrown here
     //lines not reached if exception thrown
} catch (Exception e) {
    //lines reached only when exception is thrown
} finally {
    // always executed when the try block is exited
    //independent of an exception thrown or not
}

finally 块阻止执行...

  • 当你打电话System.exit(0);
  • 如果 JVM 退出。
  • JVM 中的错误
于 2018-04-16T06:01:09.333 回答
5

如果抛出异常,finally 运行。如果没有抛出异常,finally 运行。如果异常被捕获,finally 运行。如果没有捕获到异常,finally 运行。

只有当 JVM 退出时它不运行。

于 2011-10-13T16:01:55.700 回答
5

在几个独特的场景中,在 return 之后不会调用 finally 块:如果首先调用 System.exit(),或者如果 JVM 崩溃。

让我尝试以最简单的方式回答您的问题。

规则 1:finally 块总是运行(虽然有例外。但让我们坚持一段时间。)

规则 2:finally 块中的语句在控制离开 try 或 catch 块时运行。控制的转移可以作为正常执行、break 、 continue、goto 或 return 语句的执行,或 a传播异常。

在返回语句的情况下(因为它的标题),控件必须离开调用方法,因此调用相应的 try-finally 结构的 finally 块。return 语句在 finally 块之后执行。

如果 finally 块中也有 return 语句,它肯定会覆盖 try 块中未决的语句,因为它清除了调用堆栈。

您可以在这里参考更好的解释:http: //msdn.microsoft.com/en-us/ .... 这个概念在所有高级语言中基本相同。

于 2017-11-09T09:41:41.930 回答
5

是的,写在这里

如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。

于 2018-04-02T16:06:12.670 回答
4

试试这段代码,你会明白finally 块中的代码是在 return 语句之后执行的

public class TestTryCatchFinally {
    static int x = 0;

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

    public static int f1(){
        try{
            x = 1;
            return x;
        }finally{
            x = 2;
        }
    }

    public static int f2(){
        return x;
    }
}
于 2012-04-17T09:06:56.140 回答
4

无论是否处理异常,finally 块始终执行。如果在 try 块之前发生任何异常,则 finally 块将不会执行。

于 2014-02-17T08:48:25.997 回答
3

因为无论你有什么情况,总决赛都会被调用。你没有异常,它仍然被调用,捕获异常,它仍然被调用

于 2010-05-13T06:19:47.347 回答
3

在正常的执行过程中考虑这一点(即没有抛出任何异常):如果方法不是“void”,那么它总是显式地返回一些东西,然而,最终总是被执行

于 2010-05-13T11:50:14.550 回答
3

finally如果 an 在嵌套Exception中为thrown ,也可以提前退出。编译器将警告您该块未正常完成或给出您有无法访问的代码的错误。仅当不在条件语句或循环内时才会显示无法访问代码的错误。finallyfinallythrow

try{
}finally{
   try{
   }finally{
      //if(someCondition) --> no error because of unreachable code
      throw new RunTimeException();
   }
   int a = 5;//unreachable code
}
于 2016-04-28T22:11:32.080 回答
3

与以下代码相同:

static int f() {
    while (true) {
        try {
            return 1;
        } finally {
            break;
        }
    }
    return 2;
}

f 将返回 2!

于 2016-07-04T14:53:53.153 回答
3

是的,它总是会被调用,但在一种情况下,当你使用 System.exit() 时它不会调用

try{
//risky code
}catch(Exception e){
//exception handling code
}
finally(){
//It always execute but before this block if there is any statement like System.exit(0); then this block not execute.
}
于 2016-09-13T05:36:30.857 回答
2

即使您在 try 块中放置了 return 语句,finally 块也会始终执行。finally 块将在 return 语句之前执行。

于 2018-04-20T23:57:32.020 回答
2

finally 总是在最后被调用

当你尝试时,它会执行一些代码,如果在 try 中发生了某些事情,那么 catch 将捕获该异常并且你可以打印一些 mssg 或抛出错误,然后执行 finally 块。

finally 通常在进行清理时使用,例如,如果您在 java 中使用扫描仪,您可能应该关闭扫描仪,因为它会导致其他问题,例如无法打开某些文件

于 2018-05-09T21:52:07.790 回答
2

以下是一些可以绕过 finally 块的条件:

  1. 如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。更多关于太阳教程
  2. 正常关机 - 这发生在最后一个非守护线程退出或 Runtime.exit() (一些不错的博客)时。当一个线程退出时,JVM 会清点正在运行的线程,如果剩下的唯一线程是守护线程,它会启动有序关闭。当 JVM 停止时,任何剩余的守护线程都被放弃,finally 块不执行,堆栈不展开,JVM 就退出。应该谨慎使用守护线程,很少有处理活动可以随时安全地放弃而无需清理。特别是,将守护线程用于可能执行任何类型 I/O 的任务是很危险的。守护进程线程最好保存用于“管家”任务,例如定期从内存缓存中删除过期条目的后台线程(来源

最后一个非守护线程退出示例:

public class TestDaemon {
    private static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    System.out.println("Is alive");
                    Thread.sleep(10);
                    // throw new RuntimeException();
                }
            } catch (Throwable t) {
                t.printStackTrace();
            } finally {
                System.out.println("This will never be executed.");
            }
        }
    };

    public static void main(String[] args) throws InterruptedException {
        Thread daemon = new Thread(runnable);
        daemon.setDaemon(true);
        daemon.start();
        Thread.sleep(100);
        // daemon.stop();
        System.out.println("Last non-daemon thread exits.");
    }
}

输出:

Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
于 2019-08-07T21:53:58.210 回答
1

尝试资源示例

static class IamAutoCloseable implements AutoCloseable {
    private final String name;
    IamAutoCloseable(String name) {
        this.name = name;
    }
    public void close() {
        System.out.println(name);
    }
}

@Test
public void withResourceFinally() {
    try (IamAutoCloseable closeable1 = new IamAutoCloseable("closeable1");
         IamAutoCloseable closeable2 = new IamAutoCloseable("closeable2")) {
        System.out.println("try");
    } finally {
        System.out.println("finally");
    }
}

测试输出:

try
closeable2
closeable1
finally
于 2020-02-08T04:45:25.507 回答
0

我在这里回答太晚了,但我很惊讶没有人提到 Java 调试器选项来删除堆栈帧。我是 IntelliJ 中此功能的重度用户。(我确信Eclipse 和 NetBeans 支持相同的功能。)

如果我从 try 或 catch 块中删除堆栈帧,然后是 finally 块,IDE 将提示我:“我应该执行 finally 块吗?” 显然,这是一个人工的运行时环境——一个调试器!

要回答你的问题,我想说你只能保证它在附加调试器时忽略它运行,并且(就像其他人所说)方法something()不(a)调用 Java 方法System.exit(int)或(b)C 函数exit(int)/abort()通过 JNI 或(c)做一些疯狂的事情,比如kill -9 $PID自己打电话(!)。

于 2022-01-07T15:19:04.970 回答
0

公认的答案几乎在所有方面都是正确的,但它仍然只是一半的真相(好吧,95% 的真相)。

假设以下代码:

private final Lock m_Lock = new ReentrantLock();
…
public final SomeObject doSomething( final SomeObject arg )
{
  final SomeObject retValue;
  try
  {
    lock.lock();
    retValue = SomeObject( arg );
  }
  finally
  {
    out.println( "Entering finally block");
    callingAnotherMethod( arg, retValue );
    lock.unlock();
  }
  
  return retValue;
}
…
try
{
   final var result = doSomething( new SomeObject() );
}
catch( final StackOverflowError e ) { /* Deliberately ignored */ }

调用该方法doSomething()StackOverflowError几乎立即导致。

并且lock不会被释放!

finally但是,当块总是被执行(除了已在接受的答案中列出的例外)时,怎么会发生这种情况呢?

那是因为无法保证块中的所有语句都真正执行!finally

System.exit()如果在调用之前有调用或throws语句,这将是显而易见的lock.unlock()

但是示例代码中没有这样的东西……</p>

finally除了调用之前块中的另外两个方法调用lock.unlock()将导致另一个StackOverflowError......</p>

瞧,锁没有被释放!

尽管这样的示例代码很愚蠢,但在许多软件中都可以找到很多类似的模式。只要finally块中没有发生任何丑陋的事情,一切都可以正常工作......</p>

有趣的事实是它在 Java 的更高版本中不起作用(意味着在更高版本中,锁被释放了……)。不知道何时以及为什么会发生这种变化。

但是你仍然必须确保finally块总是正常终止,否则它是否总是被执行可能并不重要......</p>

于 2022-01-24T22:15:15.480 回答