How does Java's System.exit() work with try/catch/finally blocks?
我知道在try/catch/finally块中返回会带来一些头痛——在这种情况下,finally中的返回始终是方法的返回,即使try或catch块中的返回应该是执行的返回。
但是,这同样适用于system.exit()吗?例如,如果我有一个try块:
1 2 3 4 5 6 7 8 9 10 |
如果没有异常,将调用哪个system.exit()?如果exit是一个返回语句,那么行system.exit(1)将始终(?)被召唤。但是,我不确定exit的行为是否与return不同。
在极端情况下,代码很难(如果不是不可能的话)重现,所以我不能编写单元测试。今天晚些时候,如果我有几分钟的空闲时间,我会尝试运行一个实验,但我还是很好奇,也许有人知道答案,可以在之前提供答案,或者万一我不能运行一个实验。
不,
下面是第二个案例的一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import java.security.Permission; public class Main { public static void main(String... argv) throws Exception { System.setSecurityManager(new SecurityManager() { @Override public void checkPermission(Permission perm) { /* Allow everything else. */ } @Override public void checkExit(int status) { /* Don't allow exit with any status code. */ throw new SecurityException(); } }); System.err.println("I'm dying!"); try { System.exit(0); } finally { System.err.println("I'm not dead yet!"); System.exit(1); } } } |
包括
如果
在上述两种情况下,如果
更多详细信息(个人博客)。
其他的答案包括,如果
根据JLS第14.20.3.2节:
The effect of the translation is to put the resource specification"inside" the try statement. This allows a catch clause of an extended try-with-resources statement to catch an exception due to the automatic initialization or closing of any resource.
Furthermore, all resources will have been closed (or attempted to be closed) by the time the finally block is executed, in keeping with the intent of the finally keyword.
号
也就是说,在
下面是一些代码来证明"Try with Resources"语句中的资源也没有关闭。
我使用
1 2 3 4 5 6 7 8 9 10 11 | class TestBufferedReader extends BufferedReader { public TestBufferedReader(Reader r) { super(r); } @Override public void close() throws IOException { System.out.println("close!"); super.close(); } } |
。
然后在try with resources语句中设置了调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | public static void main(String[] args) { try (BufferedReader reader = new TestBufferedReader(new InputStreamReader(System.in))) { System.out.println("In try"); System.exit(0); } catch (Exception e) { System.out.println("Exception of type" + e.getClass().getName() +" caught:" + e.getMessage()); } finally { System.out.println("finally!"); } } |
输出:
In try
号
因此,不仅
无论发生什么,最终块都将被执行…即使try块抛出任何可丢弃的(异常或错误)……
唯一不执行的case finally块是调用System.exit()方法..
1 2 3 4 5 6 7 8 |
号
它不会执行finally块。程序将终止在System.Exit()语句之后。
如果您认为这种行为有问题,并且需要对您的
我正在考虑用自己的静态方法包装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | //in initialization logic: Thread.setDefaultUncaughtExceptionHandler((thread, exception) -> { if(exception instanceof SystemExitEvent){ System.exit(((SystemExitEvent)exception).exitCode); } }) // in"main flow" or"close button" or whatever public void mainFlow(){ try { businessLogic(); Utilities.exit(0); } finally { cleanUpFileSystemOrDatabaseConnectionOrWhatever(); } } //... class Utilities { // I'm not a fan of documentaiton, // but this method could use it. public void exit(int exitCode){ throw new SystemExitEvent(exitCode); } } class SystemExitEvent extends Throwable { private final int exitCode; public SystemExitEvent(int exitCode){ super("system is shutting down") this.exitCode = exitCode; } } |
。
这个策略还有一个额外的"好处",就是使这个逻辑可测试:要测试包含"主流"的方法实际上请求系统退出,我们所要做的就是捕获一个可丢弃的,断言为写类型。例如,我们的业务逻辑包装器的测试可能如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //kotlin, a really nice language particularly for testing on the JVM! @Test fun `when calling business logic should business the business`(){ //setup val underTest = makeComponentUnderTest(configureToReturnExitCode = 42); //act val thrown: SystemExitEvent = try { underTest.mainFlow(); fail("System Exit event not thrown!") } catch(event: SystemExitEvent){ event; } //assert assertThat(thrown.exitCode).isEqualTo(42) |
。
这种策略的主要缺点是它是一种从异常流中获取功能的方法,这通常会产生意想不到的结果。在本例中,最明显的一点是,您编写
总的来说,这对我来说似乎是一个很好的策略。这里还有人这么认为吗?
在下面的示例中,如果
如果
- 当出现异常时,最后执行块
- 如果不存在异常,则不执行finally块
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | package com.exception; public class UserDefind extends Exception { private static int accno[] = {1001,1002,1003,1004,1005}; private static String name[] = {"raju","ramu","gopi","baby","bunny"}; private static double bal[] = {9000.00,5675.27,3000.00,1999.00,1600.00}; UserDefind(){} UserDefind(String str){ super(str); } public static void main(String[] args) { try { //System.exit(0); -------------LINE 1--------------------------------- System.out.println("accno"+"\t"+"name"+"\t"+"balance"); for (int i = 0; i < 5; i++) { System.out.println(accno[i]+"\t"+name[i]+"\t"+bal[i]); //rise exception if balance < 2000 if (bal[i] < 200) { UserDefind ue = new UserDefind("Balance amount Less"); throw ue; }//end if }//end for //System.exit(0);-------------LINE 2--------------------------------- }//end try catch (UserDefind ue) { System.out.println(ue); } finally{ System.out.println("Finnaly"); System.out.println("Finnaly"); System.out.println("Finnaly"); } }//end of main }//end of class |