Program Tip

Java의 System.exit ()는 try / catch / finally 블록과 어떻게 작동합니까?

programtip 2020. 11. 8. 10:56
반응형

Java의 System.exit ()는 try / catch / finally 블록과 어떻게 작동합니까?


이 질문에 이미 답변이 있습니다.

try / catch / finally 블록에서 반환하는 것과 관련된 골칫거리를 알고 있습니다. try 또는 catch 블록의 반환이 실행되어야하는 경우에도 finally의 반환이 항상 메서드에 대한 반환 인 경우입니다.

그러나 System.exit ()에도 동일하게 적용됩니까? 예를 들어 try 블록이있는 경우 :

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

예외가 없으면 어떤 System.exit ()가 호출됩니까? exit가 return 문이면 System.exit (1) 줄은 항상 (?) 호출됩니다. 그러나 exit가 return과 다르게 작동하는지 확실하지 않습니다.

코드는 불가능하지는 않지만 재현하기가 매우 어려운 극단적 인 경우이므로 단위 테스트를 작성할 수 없습니다. 나는 오늘 나중에 실험을 시도 할 것입니다. 몇 분의 여유 시간이 있으면 어쨌든 궁금합니다. 아마도 SO의 누군가가 답을 알고 답을 제공 할 수 있습니다. 실험.


아니오. System.exit(0)반환되지 않으며 finally 블록은 실행되지 않습니다.

System.exit(int)던질 수 있습니다 SecurityException. 이 경우 finally 블록 실행됩니다. 그리고 동일한 주체가 동일한 코드베이스에서 동일한 메서드를 호출하기 SecurityException때문에 두 번째 호출에서 다른 메서드 가 throw 될 가능성이 있습니다.


두 번째 경우의 예는 다음과 같습니다.

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

}

포함하여 간단한 테스트 catch도는 경우 것으로 밝혀 system.exit(0)보안 예외를 throw하지 않습니다, 그것은 마지막으로 실행 된 문을 것입니다 ( catchfinally전혀 실행되지 않습니다).

If system.exit(0)보안 예외가 발생 catch하고 finally명령문이 실행됩니다. 두 경우 catch와는 finally포함 system.exit()문이 앞의 문에만 system.exit()문이 실행됩니다.

위에서 설명한 두 경우 모두 try코드가 다른 메서드에서 호출 된 메서드에 속하면 호출 된 메서드가 반환되지 않습니다.

자세한 내용은 여기 (개인 블로그)를 참조 하세요 .


다른 답변 은를 던지지 않고 JVM을 종료하는 경우 catchfinally블록이 실행되지 않는 방법을 다루었 지만 리소스에 대한 "try-with-resources"블록에서 어떤 일이 발생하는지 보여주지 않습니다. 닫혀 있습니까?System.exitSecurityException

JLS, 섹션 14.20.3.2 에 따르면 :

변환의 효과는 리소스 사양을 try 문 "내부"에 넣는 것입니다. 이렇게하면 확장 된 try-with-resources 문의 catch 절이 리소스의 자동 초기화 또는 닫기로 인해 예외를 포착 할 수 있습니다.

또한 finally 키워드의 의도에 따라 finally 블록이 실행될 때 모든 리소스가 닫히거나 닫히려고 시도됩니다.

즉, 또는 블록이 실행 close되기 전에 리소스가 d 가됩니다. 그들은 무엇을하는 경우 경우에도 어떻게 든 거라고 실행되지 않습니다?catchfinallyclosecatchfinally

다음은 "try-with-resources"문의 리소스도 닫히지 않음을 보여주는 코드입니다.

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.exittry-with-resources 문에서 호출하는 테스트 케이스를 설정했습니다 .

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

산출:

시도 중

따라서 do catchfinally블록이 실행 되지 않을뿐만 아니라 "try-with-resources"문이 성공하면 close리소스에 대한 기회를 얻지 못합니다 System.exit.


finally 블록은 무슨 일이 있어도 실행됩니다 .... try 블록이 throwable (예외 또는 오류)을 던지더라도 .....

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 () 문 이후에 종료됩니다.


이 동작에 문제가 있다고 생각하고 System.exit호출을 세밀하게 제어해야하는 경우 수행 할 수있는 유일한 작업은 자체 논리에 System.exit 기능을 래핑하는 것입니다. 그렇게하면 최종적으로 블록을 실행하고 종료 흐름의 일부로 리소스를 닫을 수 있습니다.

내가 고려하고있는 것은 System.exit내 자신의 정적 메서드에서 호출 및 기능을 래핑하는 것입니다. 내 구현에서 또는 exit의 사용자 지정 하위 클래스를 throw하고 해당 예외를 처리하기 위해 사용자 지정 Uncaught 예외 처리기를 구현합니다 . 따라서 내 코드는 다음과 같습니다.ThrowableErrorThread.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;
  }
} 

This strategy has the added "benefit" of making this logic testable: to test that the method containing our "main flow" actually requests the system to exit, all we have to do is catch a throwable and assert that is the write type. For example, a test for our business logic wrapper might look like:

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

The major downside to this strategy is that it is a way of getting functionality out of exception flow, which often has unintended consequences. The most obvious one, in this case, is that anywhere you've written try { ... } catch(Throwable ex){ /*doesnt rethrow*/ } will have to be updated. In the case of libraries that have custom execution contexts, they will need to be retrofitted to also understand this exception.

On balance, this seems like a good strategy to me. Does anybody else here think so?


  1. In example below, if System.exit(0) is before the exception line, the program will be terminated normally, so the FINALLY will not execute.

  2. If the System.exix(0) is the last line of the try block, here we have 2 scenarios

    • when exception is present then finally block is executed
    • when exception is not present then finally block is not executed

.

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

참고URL : https://stackoverflow.com/questions/1410951/how-does-javas-system-exit-work-with-try-catch-finally-blocks

반응형