55

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

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 ()이 호출됩니까? exit가 return 문인 경우 System.exit (1) 줄이 항상 호출 (?)됩니다. 그러나 출구가 반환과 다르게 동작하는지 확실하지 않습니다.

코드는 극단적 인 경우 재현하기가 불가능하지는 않더라도 매우 어렵 기 때문에 단위 테스트를 작성할 수 없습니다. 나는 나중에 약간의 자유 분을 얻으려고 나중에 실험을하려고 노력할 것이다. 그러나 어쨌든 나는 호기심이 많다. 아마도 누군가가 그 대답을 알고 있고 그것을 제공 할 수있다. 실험.


  • 시험하기 어려운이 극단적 인 경우는 어떻습니까? - JRL
  • 내가 제공 한 코드가 아닙니다. 그러나 테스트를 작성하는 데 시간이 소요됩니다 (더 이상 필요하지 않습니다, 에릭슨 덕분에). - Thomas Owens
  • 질문하는 정확한 질문에 답하기 위해서는 테스트를 위해 한 줄의 추가 코드가 필요합니다.throw new Exception("Error");바로 전에System.exit(0)실행 파일이 반환하는 상태 코드를 컴파일하고 봅니다. - Ki Jéy

6 답변


70

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

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

}


  • 또한StackOverflowException을 예방하기 위해System.exit스택 프레임이 호출되면System.exit스택 한도 바로 앞에 있습니다. 이러한 종류의 경계 조건은 때때로 해커에 의해 조작 될 수 있으므로이 문제에 의존하는 보안 불변성이있는 경우Thread.UncaughtExceptionHandler그것은 깊이있는 방어 수단으로 존재합니다. - Mike Samuel
  • 이 질문에 OP가 제공하는 것과 동일한 코드 블록이있는 곳에서 자주 발생하는 경우를 추가합니다.finally실행중인 블록 (ifAnt개미에 의존하는 응용 프로그램 시작 스크립트로 사용하고 있습니다.java작업) 또는 실행되지 않는 경우 (응용 프로그램이java콘솔에서Ant). 이 답변을 기반으로 볼 때 응용 프로그램이 Ant의 내부에서 호출 될 때java과제 aSecurityException던졌습니다. - Marcus Junius Brutus
  • StackOverflowException(당신이 정의하지 않는 한) 존재하지 않습니다. 그것은StackOverflowError. 중요한 작은 차이. - Peter Verhas

7

다음을 포함한 간단한 테스트catchifsystem.exit(0)보안 예외를 throw하지 않습니다. 마지막으로 실행 된 명령문이됩니다.catchfinally전혀 실행되지 않습니다).

만약system.exit(0)보안 예외를 throw합니다.catchfinally명령.이 실행됩니다. 둘 다catchfinally있다system.exit()진술, 이보다 앞선 진술system.exit()명령.이 실행됩니다.

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

자세한 내용은이리(개인 블로그).


  • 귀한 물건을 돌봐 주셔서 감사합니다. :) - Andrew Barber

3

다른 해답은catchfinally블록이 실행되지 않는 경우System.exit던지지 않고 JVM을 종료합니다.SecurityException, 자원에 대한 "자원과 함께 시도"블록에서 어떤 일이 일어나는지 보여주지는 않습니다.

에 따르면JLS, 섹션 14.20.3.2:

변환의 효과는 자원 스펙을 "내부"try 문에 넣는 것입니다. 이를 통해 확장 된 try-with-resources 문의 catch 절을 사용하여 자원의 자동 초기화 또는 닫기로 인해 예외를 catch 할 수 있습니다.

또한 finally 블록의 의도에 따라 finally 블록이 실행될 때까지 모든 리소스가 닫혔습니다 (닫히기도합니다).

즉, 자원은close전에 dcatch또는finally블록 실행. 그들이 어때?close어쨌든catchfinally도망 간다?

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

산출:

시도 중

따라서,catchfinally블록이 실행되지 않으면 "try-with-resources"문이 실행되지 않습니다.close그 자원System.exit성공합니다.


3

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 () 문 다음에.


1

이 문제가 문제가되는 것으로 생각하고System.exit호출하면 System.exit 기능을 자신의 논리에 랩핑하면됩니다. 그렇게하면 최종 블록을 실행하고 종료 흐름의 일부로 리소스를 닫을 수 있습니다.

내가하고있는 일은System.exit전화 & amp; 기능을 내 정적 메서드입니다. 내 구현에exit나는 사용자 정의 서브 클래스를 던질 것이다.Throwable또는Error다음과 같이 사용자 정의 Uncaught 예외 처리기를 구현합니다.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;
  }
} 

이 전략은이 로직을 테스트 가능하게 만드는 "이점"을 추가했습니다. "메인 플로우"를 포함하는 메소드가 실제로 시스템을 종료하도록 테스트하려면, 우리가해야 할 일은 throwable을 잡아서 쓰기 유형이라고 주장하는 것입니다. 예를 들어 비즈니스 로직 래퍼에 대한 테스트는 다음과 같습니다.

//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*/ }업데이트해야합니다. 사용자 정의 실행 컨텍스트가있는 라이브러리의 경우이 예외를 이해하기 위해 개조해야합니다.

균형을 이룰 수있는 좋은 전략 인 것 같습니다. 다른 사람들이 그렇게 생각하니?


0

  1. 아래 예에서 ifSystem.exit(0)예외 행 앞에 있으면 프로그램이 정상적으로 종료되므로 FINALLY가 실행되지 않습니다.

  2. 만약System.exix(0)try 블록의 마지막 줄입니다. 여기에 2 개의 시나리오가 있습니다.

    • 예외가 존재하면 finally 블록이 실행됩니다.
    • 예외가 존재하지 않으면 finally 블록이 실행되지 않습니다.

.

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

연결된 질문


관련된 질문

최근 질문