如何Java的System.exit()的使用try / catch / finally块工作吗?

2019-07-17 18:08发布

这个问题已经在这里有一个答案:

  • 是否finally块总是得到Java的执行? 46个回答

我知道它会涉及到的try / catch / finally块返回头疼的 - 情况下,在最后的回报始终是方法的返回,即使在try或catch块一回应该执行的一个。

然而,也同样适用于System.exit()的? 举例来说,如果我有一个try块:

try {
    //Code
    System.exit(0)
}
catch (Exception ex) {
    //Log the exception
}
finally {
    System.exit(1)
}

如果没有异常,这System.exit()的会叫什么名字? 如果出口是一个return语句,那么该行System.exit(1)总是(?)被调用。 不过,我不知道,如果退出的行为与收益不同。

该代码是在这是非常困难的,如果不是不可能的,为了再现一个极端的例子,所以我不能写一个单元测试。 我要去尝试运行实验后的今天,如果我得到一些免费分钟,但我很好奇,无论如何,也许有人对SO知道答案,可以之前或在情况下,我不能运行它提供实验。

Answer 1:

System.exit(0)不返回,并且不执行最终块。

System.exit(int)可以抛出一个SecurityException 。 如果出现这种情况,finally块被执行。 而且,由于相同的主要是调用从相同的代码库相同的方法,另一个SecurityException很可能是从第二个呼叫抛出。


下面是第二种情况的一个例子:

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

}


Answer 2:

简单的测试,包括catch太透露,如果system.exit(0)不会引发安全异常,这将是最后一个执行的语句( catchfinally根本不被执行)。

如果system.exit(0)并抛出一个安全异常, catchfinally的语句被执行。 如果同时catchfinally包含system.exit()语句,只有这些语句之前system.exit()语句被执行。

在上面的描述下这两种情况下,如果try代码属于通过其他方法调用的方法,调用的方法不返回。

更多细节在这里 (个人博客)。



Answer 3:

其他答案已经介绍如何catchfinally如果块不运行System.exit退出JVM没有抛出SecurityException ,但他们没有表现出一个“尝试-与资源”区块的资源会发生什么:他们是关闭?

按照JLS,第14.20.3.2 :

翻译的作用是把资源规范“内部” try语句。 这允许扩展的尝试,与资源语句来捕捉异常的catch子句所导致的任何资源的自动初始化或关闭。

此外,所有的资源将被关闭(或试图闭合)由执行最后块的时间,以与的意图保持最后关键字。

也就是说,资源将close d一个之前catchfinally阻止运行。 如果他们是close Ð不知何故,即使catchfinally不跑?

下面是一些代码,以证明在“尝试与 - 资源”的语句资源也不关闭。

我用一个简单的子类BufferedReader ,调用之前打印一份声明super.close

class TestBufferedReader extends BufferedReader {
    public TestBufferedReader(Reader r) {
        super(r);
    }

    @Override
    public void close() throws IOException {
        System.out.println("close!");
        super.close();
    }
}

然后,我设置了呼叫的测试用例System.exit在try-与资源的语句。

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

输出:

在试

因此,不仅catchfinally块无法运行,一个“尝试与-资源”的语句将没有机会来close它的资源,如果System.exit成功。



Answer 4:

finally块将不管执行的....即使try块抛出任何抛出(异常或错误)......

唯一的案件finally块不执行......当我们调用System.exit()方法..

try{
    System.out.println("I am in try block");
    System.exit(1);
} catch(Exception ex){
    ex.printStackTrace();
} finally {
    System.out.println("I am in finally block!!!");
}

它不会执行finally块。 该计划将后System.exit()的语句被终止。



Answer 5:

如果您认为这种行为有问题,你需要很好地控制你的System.exit电话,那么你可以做的唯一的事情是在你自己的逻辑绕了System.exit功能。 如果我们这样做,我们可以得到最终的执行块,并获得资源封闭,我们的出口流的一部分。

我正在考虑做的是包裹System.exit调用和功能在我自己的静态方法。 我在执行的exit我会抛出的自定义子类ThrowableError ,并实现了自定义的未捕获异常处理程序Thread.setDefaultUncaughtExceptionHandler来处理异常。 因此,我的代码就变成了:

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

这种策略使得该逻辑可测试的附加“利”:来测试包含我们的“主流”的方法实际上是要求系统退出,我们所要做的就是赶上抛出并断言是写类型。 例如,对于我们的业务逻辑封装测试可能类似于:

//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)

主要缺点这种策略是,它是让出功能异常流动,往往已意想不到的后果的一种方式。 最明显的一个,在这种情况下,是任何地方,你已经写了try { ... } catch(Throwable ex){ /*doesnt rethrow*/ }将不得不进行更新。 在具有自定义执行上下文库的情况下,他们将需要进行改装也明白这一点例外。

总的来说,这似乎是一个很好的策略给我。 有没有人在这里这样认为吗?



Answer 6:

  1. 在下面的例子中,如果System.exit(0)是个例外行之前,该程序将被正常终止,所以最终将不会执行。

  2. 如果System.exix(0)是try块的最后一行,在这里我们有2个场景

    • 当异常存在,则最后被执行块
    • 当异常是不存在,则最终,不执行块

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


文章来源: How does Java's System.exit() work with try/catch/finally blocks? [duplicate]