Jak działa system Javy.exit () działa z blokami try/catch / finally? [duplikat]
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.
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);
}
}
}
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).
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ą close
d 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.
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 ().
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?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
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.-
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
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