Как работает система Java.выход () работа с блоками try / catch / finally? [дубликат]



этот вопрос уже есть ответ здесь:




  • Всегда ли блок finally выполняется на Java?

    48 ответов



Я знаю о головных болях, которые включают возврат в блоки try / catch / finally-случаи, когда возврат в finally всегда является возвратом для метода, даже если возврат в блоке try или catch должен быть одним выполненный.



однако то же самое относится и к системе.выход()? Например, если у меня есть блок try:



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


если нет исключений, то какая система.exit() будет вызван? Если выход был оператором return,то система line.выход(1) всегда (?) быть вызванным. Однако я не уверен, что exit ведет себя иначе, чем return.



код в крайнем случае очень трудно, если не невозможно, воспроизвести, поэтому я не могу написать модульный тест. Я попытаюсь провести эксперимент позже сегодня, если у меня будет несколько свободных минут, но мне все равно любопытно, и, возможно, кто-то из SO знает ответ и может предоставить его до или в случае, если я не могу провести эксперимент.

391   6  

6 ответов:

нет. System.exit(0) не возвращается, и блок finally не выполняется.

System.exit(int) можете кинуть SecurityException. Если это произойдет, то окончательно блок будет быть казнен. И поскольку тот же Принципал вызывает тот же метод из той же базы кода, другой 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);
    }
  }

}

простые тесты, в том числе catch тоже показать, что если system.exit(0) не вызывает исключение безопасности, это будет последний выполненный оператор (catch и finally не выполняется вообще).

если system.exit(0) вызывает исключение безопасности,catch и finally инструкции выполняются. Если оба catch и finally содержат system.exit() заявления, только заявления, предшествующие этим system.exit() инструкции выполняются.

в обоих случаях, описанных выше, если try код принадлежит методу, вызываемому другим методом, вызываемый метод не возвращает.

более подробная информация здесь (личный блог).

блок finally будет выполнен несмотря ни на что....даже если попробовать блокировать броски любым Throwable(исключение или сообщение об ошибке).....

только в случае, если блок finally не выполняется...это когда мы называем системой.метод 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. Программа будет прекращена после системы.оператор Exit.

другие ответы охватили как catch и finally блоки не работают, если System.exit выходит из JVM, не бросая SecurityException, но они не показывают, что происходит в блоке "try-with-resources" для ресурсов: они закрыты?

по словам JLS, раздел 14.20.3.2:

эффект перевода заключается в том, чтобы поместить спецификацию ресурса "внутри" оператора try. Это позволяет использовать предложение catch расширенного оператор try-with-resources для перехвата исключения из-за автоматической инициализации или закрытия любого ресурса.

кроме того, все ресурсы будут закрыты (или попытаются быть закрыты) к моменту выполнения блока finally, в соответствии с намерением ключевого слова finally.

то есть ресурсы будут closeг до catch или finally блок работает. Что, если они close d как-то даже если catch и finally не бежать?

вот некоторый код, чтобы продемонстрировать, что ресурсы в операторе "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.exit в инструкции 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!");
    }
}

выход:

в try

таким образом, не только catch и finally блоки не запускаются, оператор "try-with-resources" не получит шанса close свои ресурсы, если System.exit успешно.

  1. в примере ниже, если System.exit(0) находится перед строкой исключения, программа будет завершена нормально, поэтому окончательно не будет выполняться.

  2. если System.exix(0) это последняя строка блока try, здесь у нас есть 2 сценария

    • когда исключение присутствует, то, наконец, блок выполняется
    • если исключений нету, то блок 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

если вы считаете это поведение проблематичным, и вам нужен точный контроль над вашим System.exit звонит, то единственное, что вы можете сделать, это обернуть системе.выход из функциональности в вашей собственной логике. Если мы это сделаем, мы можем получить, наконец, блоки выполнены и получить ресурсы закрыты как часть нашего выходного потока.

то, что я собираюсь сделать, это обернуть System.exit вызов & функциональность в моем собственном статическом методе. В моей реализации exit Я бы бросил пользовательский подкласс Throwable или Error, и реализовать пользовательский обработчик неперехваченных исключений с 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*/ } придется обновить. В случае библиотек, которые имеют пользовательские контексты выполнения, они должны быть модифицированы, чтобы также понять это исключение.

в целом, это кажется мне хорошей стратегией. Кто-нибудь еще здесь так думает?

Comments

    Ничего не найдено.