Jak działa system Javy.exit () działa z blokami try/catch / finally? [duplikat]

to pytanie ma już odpowiedzi tutaj : czy blok finally zawsze jest wykonywany w Javie? (49 odpowiedzi) Zamknięty 4 lata temu .

Jestem świadomy bólów głowy, które wiążą się z powrotem w blokach try / catch / finally-przypadki, w których zwrot w bloku finally jest zawsze zwrotem dla metody, nawet jeśli zwrot w bloku try lub catch powinien być wykonywany.

Jednak to samo dotyczy systemu.exit ()? Na przykład, jeśli mam blok try:

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

Jeśli nie ma wyjątków, który System.exit() zostanie wywołane? Jeśli exit jest deklaracją return, To system liniowy.exit (1) would always (?) be called. Nie jestem jednak pewien, czy exit zachowuje się inaczej niż return.

Kod jest w skrajnym przypadku, który jest bardzo trudny, jeśli nie niemożliwy do odtworzenia, więc nie mogę napisać testu jednostkowego. Mam zamiar spróbować uruchomić eksperyment dzisiaj, jeśli dostanę kilka darmowych minut, ale i tak jestem ciekawy, a może ktoś na tak zna odpowiedź i może dostarczyć go przed lub w przypadku, gdy nie mogę uruchomić eksperymentu.

Author: Thomas Owens, 2009-09-11

6 answers

Nie. System.exit(0) nie zwraca, a ostatecznie blok nie jest wykonywany.

System.exit(int) może rzucać SecurityException. Jeśli tak się stanie, zostanie wykonany blok . A ponieważ ten sam główny wywołuje tę samą metodę z tej samej bazy kodu, inne SecurityException prawdopodobnie zostanie wyrzucone z drugiego wywołania.


Oto przykład drugiego przypadku:
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);
    }
  }

}
 85
Author: erickson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-11 13:54:11

Proste testy, w tym również catch ujawniają, że jeśli system.exit(0) nie wyrzuci wyjątku bezpieczeństwa, będzie to ostatnia wykonana Instrukcja (catch i finally nie zostaną wykonane w ogóle).

Jeśli system.exit(0) rzuca wyjątek bezpieczeństwa, wykonywane są polecenia catch i finally. Jeśli zarówno catch, jak i finally zawierają system.exit(), wykonywane są tylko polecenia poprzedzające te system.exit().

W obu przypadkach opisanych powyżej, jeśli kod try należy do metody wywołanej inną metodą, wywołana metoda nie zwraca.

Więcej szczegółów tutaj (osobisty blog).

 10
Author: Jérôme Verstrynge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-30 12:51:28

Inne odpowiedzi dotyczyły tego, jak bloki catch i finally nie działają, jeśli System.exit opuszczają JVM bez rzucania SecurityException, ale nie pokazują, co dzieje się w bloku "try-with-resources" do zasobów: czy są zamknięte?

Zgodnie z JLS, sekcja 14.20.3.2:

Efektem tłumaczenia jest umieszczenie specyfikacji zasobów "wewnątrz" instrukcji try. Pozwala to klauzuli catch rozszerzonej instrukcji try-with-resources na wyłapanie wyjątku ze względu na automatyczne Inicjowanie lub zamykanie dowolnego zasobu.

Ponadto, wszystkie zasoby zostaną zamknięte (lub będą próbowane zostać zamknięte) przed wykonaniem bloku finally, zgodnie z intencją słowa kluczowego finally.

Oznacza to, że zasoby będą close d przed uruchomieniem catch lub finally bloku. Co jeśli są closed jakoś nawet jeśli catch i finally nie biegną?

Oto jakiś kod, aby wykazać, że zasoby w " try-with-resources" oświadczenie też nie jest zamknięte.

Używam prostej podklasy BufferedReader, która wypisuje polecenie przed wywołaniem super.close.

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

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

Następnie ustawiłem testowy przypadek wywołania System.exit w instrukcji try-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!");
    }
}

Wyjście:

W try

Dlatego nie tylko catch i finally bloki nie działają, ale instrukcja "try-with-resources" nie będzie miała szansy na close swoje zasoby, Jeśli System.exit się powiedzie.

 7
Author: rgettman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

Ostatecznie blok zostanie wykonany bez względu na wszystko....nawet jeśli try block rzuca dowolny throwable (wyjątek lub błąd).....

Only case finally block does not execute...is kiedy zadzwonimy do systemu.metoda 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!!!");
}

Nie wykona finally block. Program zostanie zakończony po systemie.polecenie exit ().

 3
Author: Chinmoy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-20 20:46:50

Jeśli uważasz to zachowanie za problematyczne i potrzebujesz kontroli nad wywołaniami System.exit, jedyną rzeczą, którą możesz zrobić, to zawinąć System.Zakończ funkcjonalność we własnej logice. Jeśli to zrobimy, możemy w końcu wykonać bloki i zamknąć zasoby w ramach naszego przepływu wyjścia.

Rozważam zrobienie zawijania System.exit wywołania i funkcjonalności w mojej własnej metodzie statycznej. W mojej implementacji exit rzuciłbym niestandardową podklasę Throwable lub Error i zaimplementował custom Uncaught exception handler with Thread.setDefaultUncaughtExceptionHandler to handle that exception. Tak więc mój kod staje się:

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

Ta strategia ma dodatkową " korzyść "z uczynienia tej logiki testowalną: aby sprawdzić, czy metoda zawierająca nasz" główny przepływ " faktycznie wymaga wyjścia z Systemu, wystarczy złapać throwable i potwierdzić, że jest to typ zapisu. Na przykład, test dla naszego opakowania logiki biznesowej może wyglądać następująco:

//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)
[[9]}głównym minusem tej strategii jest to, że jest to sposób na uzyskiwanie funkcjonalności z przepływu WYJĄTKÓW, co często ma niezamierzone konsekwencje. Najbardziej oczywistym w tym przypadku jest to, że gdziekolwiek napisałeś try { ... } catch(Throwable ex){ /*doesnt rethrow*/ }, będzie musiał zostać zaktualizowany. W przypadku bibliotek, które mają niestandardowe konteksty wykonania, będą musiały zostać zmodernizowane, aby również zrozumieć ten wyjątek. Dla mnie to dobra strategia. Czy ktoś jeszcze tak uważa?
 3
Author: Groostav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-19 17:53:43
  1. W przykładzie poniżej, Jeśli System.exit(0) znajduje się przed linią exception, program zostanie normalnie zakończony, więc FINALLY nie zostanie uruchomiony.

  2. Jeśli System.exix(0) jest ostatnią linią bloku try, tutaj mamy 2 scenariusze

    • gdy występuje wyjątek, w końcu blok jest wykonywany
    • gdy wyjątek nie jest obecny, ostatecznie blok nie jest wykonywany

.

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
 0
Author: honey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-15 05:42:44