Как работает система Java.exit () работа с блоками try/catch/finally? [дубликат]
этот вопрос уже есть ответ здесь:
- всегда ли блок finally выполняется на Java? 48 ответов
Я знаю о головных болях, которые включают возвращение в try/catch / finally blocks-случаи, когда возврат в finally всегда является возвратом для метода, даже если возврат в блоке try или catch должен быть тот, которого казнили.
однако то же самое относится к системе.exit()? Например, если у меня есть блок try:
try {
//Code
System.exit(0)
}
catch (Exception ex) {
//Log the exception
}
finally {
System.exit(1)
}
если нет исключений, какая система.exit () будет вызван? Если exit был оператором return, то линейная система.выход(1) всегда (?) назвать. Однако я не уверен, что exit ведет себя иначе, чем return.
код в крайнем случае очень трудно, если не невозможно, воспроизвести, поэтому я не могу написать единицу тест. Я попытаюсь провести эксперимент позже сегодня, если у меня будет несколько свободных минут, но мне все равно любопытно, и, возможно, кто-то знает ответ и может предоставить его раньше или в случае, если я не смогу провести эксперимент.
6 ответов
нет. 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);
}
}
}
простые тесты, в том числе catch
тоже показать, что если system.exit(0)
не создает исключение безопасности, это будет последний выполненный оператор (catch
и finally
не выполняется вообще).
если system.exit(0)
создает исключение безопасности,catch
и finally
инструкции выполняются. Если оба catch
и finally
содержат system.exit()
утверждения, только утверждения, предшествующие этим system.exit()
инструкции выполняются.
в обоих случаях, описанных выше, если try
код принадлежит методу, вызываемому другим методом, вызываемый метод не возвращается.
более подробная информация здесь (личный блог).
блок finally будет выполнен несмотря ни на что....даже если блок try выбрасывает любой throwable (исключение или ошибку).....
только блок case 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. Программа будет прекращена после системы.оператор Exit.
другие ответы охватили как catch
и finally
блоки не работают, если System.exit
выходит из JVM, не бросая SecurityException
, но они не показывают, что происходит в блоке "try-with-resources" для ресурсов: они закрыты?
по словам JLS, раздел 14.20.3.2:
эффект перевод ставить спецификация ресурсов "внутри" попробовать заявление. Это позволяет предложение catch расширенного оператор try-with-resources, чтобы поймать исключение из-за автоматической инициализации или закрытия любого ресурса.
кроме того, все ресурсы будут закрыты (или попытаются быть закрыты) к моменту выполнения блока finally в соответствии с намерением ключевого слова finally.
то есть ресурсы будут close
d перед catch
или finally
блок работает. Что, если они ... --6-->д как-то даже если 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
успешно.
в примере ниже, если
System.exit(0)
находится перед строкой исключения, программа будет завершена нормально, поэтому, наконец, не будет выполняться.-
если
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
звонит, то единственное, что вы можете сделать, это обернуть системе.выход из функциональности в вашей собственной логике. Если мы это сделаем, мы сможем выполнить блоки finally и закрыть ресурсы как часть нашего потока выхода.
то, что я рассматриваю, это обертывание 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*/ }
придется обновить. В случае библиотек, имеющих пользовательские контексты выполнения, их необходимо будет обновить, чтобы также понять это исключение.
в целом, это кажется мне хорошей стратегией. Кто-нибудь еще так думает?