Когда следует называть System.exit в Java

В Java, в чем разница с или без System.exit(0) в следующем коде?

public class TestExit
{      
    public static void main(String[] args)
    { 
        System.out.println("hello world");

        System.exit(0);  // is it necessary? And when it must be called? 
    }      
}

В документе говорится: "Этот метод никогда не возвращается нормально" . Что это значит?

Ответ 1

System.exit() можно использовать для запуска завершающих крючков до выхода программы. Это удобный способ справиться с остановкой в ​​больших программах, где все части программы не могут (и не должны) знать друг о друге. Затем, если кто-то хочет выйти, он может просто называть System.exit(), а крючки выключения (если они правильно настроены) позаботятся о выполнении всех необходимых завершающих церемоний, таких как закрытие файлов, освобождение ресурсов и т.д.

"Этот метод никогда не возвращается нормально". означает, что метод не вернется; как только поток туда пойдет, он не вернется.

Другим, возможно, более распространенным способом выхода из программы является простое достижение конца метода main. Но если есть какие-то не-демонные потоки, они не будут закрыты и, следовательно, JVM не выйдет. Таким образом, если у вас есть какие-то такие не-демонные потоки, вам нужны другие средства (чем крючки выключения), чтобы закрыть все потоки не-демона и освободить другие ресурсы. Если нет других не-демонных потоков, возврат из main завершает работу JVM и вызывает вызовы завершения работы.

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

Ответ 2

В этом случае он не нужен. Никакие дополнительные потоки не будут запущены, вы не меняете код выхода (который по умолчанию равен 0) - в основном это бессмысленно.

Когда документы говорят, что метод никогда не возвращается нормально, это означает, что последующая строка кода становится недоступной, хотя компилятор не знает, что:

System.exit(0);
System.out.println("This line will never be reached");

Будет ли исключено либо исключение, либо виртуальная машина закончит работу перед возвратом. Он никогда не "просто вернется".

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

Ответ 3

Метод никогда не возвращается, потому что это конец мира, и ни один из ваших кодов не будет выполнен дальше.

Ваше приложение в вашем примере выйдет в любом случае в том же месте в коде, но если вы используете System.exit. у вас есть возможность вернуть пользовательский код в среду, например,

System.exit(42);

Кто будет использовать ваш код выхода? A script, который называется приложением. Работает в Windows, Unix и во всех других сценариях.

Зачем возвращать код? Говорить такие вещи, как "Мне это не удалось", "База данных не ответила".

Чтобы узнать, как получить значение od из кода выхода и использовать его в оболочке unix script или Windows cmd script, вы можете проверить этот ответ на этом сайте

Ответ 4

System.exit(0) завершает работу JVM. В простых примерах, подобных этому, трудно пережить разницу. Параметр передается обратно в ОС и обычно используется для обозначения аномального завершения (например, какая-то фатальная ошибка), поэтому, если вы вызываете java из командного файла или оболочки script, вы сможете получить это значение и получить идея, если приложение было успешным.

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

Ответ 5

В приложениях, которые могут иметь сложный крюк остановки, этот метод нельзя вызывать из неизвестного потока. System.exit никогда не выходит из строя, потому что вызов блокируется до тех пор, пока JVM не будет завершена. Это как если бы какой-либо код работал, на котором вилка питания была надета, прежде чем он сможет закончить. Вызов System.exit инициирует крючки отключения программы, и любой поток, который вызывает System.exit, будет блокироваться до завершения программы. Это подразумевает, что если крюк завершения работы отправляет задачу в поток, из которого был вызван System.exit, программа будет блокирована.

Я обрабатываю это в своем коде со следующим:

public static void exit(final int status) {
    new Thread("App-exit") {
        @Override
        public void run() {
            System.exit(status);
        }
    }.start();
}

Ответ 6

НИКОГДА не следует вызывать System.exit(0) по следующим причинам:

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

    Если ваша программа не может выйти "нормально", вы потеряли контроль над своей разработкой [дизайном]. Вы должны всегда иметь полный контроль над состоянием системы.

  3. Проблемы программирования, такие как запуск потоков, которые не были остановлены, обычно становятся скрытыми.
  4. Вы можете столкнуться с несогласованным состоянием приложения, которое прерывает потоки ненормально. (См. № 3)

Кстати: возврат кодов возврата, отличных от 0, имеет смысл, если вы хотите указать на ненормальное завершение программы.

Ответ 7

Хотя ответ был действительно полезен, но некоторые, как он пропустил некоторые дополнительные детали. Надеюсь, что ниже поможет понять процесс выключения в java, в дополнение к ответу выше:

  • При упорядоченном * выключения JVM сначала запускает все зарегистрированные крючки отключения. Крюки остановки - это нестационарные потоки, зарегистрированные в Runtime.addShutdownHook.
  • JVM не дает никаких гарантий относительно порядка, в котором крюки остановки . Если какие-либо потоки приложений (демона или nondaemon) все еще запущены во время выключения они продолжают работать одновременно с процессом останова.
  • Когда все завершающие блокировки завершены, JVM может выбрать запуск финализаторов если runFinalizersOnExit истинно, а затем останавливается.
  • JVM не пытается остановить или прервать любые потоки приложений, которые все еще работают во время выключения; они внезапно прекращаются, когда JVM в конечном итоге останавливается.
  • Если завершающие блокировки или финализаторы не завершены, тогда процесс упорядоченного выключения "зависает", и JVM должен быть отключен внезапно.
  • При резком отключении JVM не требуется ничего, кроме остановки JVM; выключения не будут выполняться.

PS: JVM может отключиться либо с помощью упорядоченного или резкого.

  • При завершении последнего "нормального" (nondaemon) потока завершается упорядоченное завершение, кто-то вызывает System.exit или другие средства для платформы (например, отправляет SIGINT или нажимает Ctrl-C).
  • Хотя выше приведен стандартный и предпочтительный способ для JVM для закрытия, его также можно отключить, вызвав Runtime.halt или путем уничтожения процесса JVM через операционную систему (например, SIGKILL).

Ответ 8

Требуется System.exit

  • когда вы хотите вернуть код ошибки не-0
  • когда вы хотите выйти из своей программы где-то, что не является основным()

В вашем случае это делает то же самое, что и простой возврат из основного.

Ответ 9

Спецификация Java Language говорит, что

Выход программы

Программа завершает всю свою деятельность и выходит, когда одна из двух вещей бывает:

Все потоки, которые не являются потоками демона, завершаются.

В некотором потоке вызывается метод exit класса Runtime или класс Система, и диспетчер безопасности не запрещает операцию выхода.

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

Ответ 10

Если у вас есть другая программа, запущенная в JVM, и вы используете System.exit, эта вторая программа также будет закрыта. Представьте себе, например, что вы запускаете java-задание в кластере node и что Java-программа, управляющая кластером node, работает в одной JVM. Если задание будет использовать System.exit, оно не только прекратит работу, но и "выключит полный node". Вы не сможете отправить другое задание в этот кластер node, так как программа управления была закрыта случайно.

Поэтому не используйте System.exit, если вы хотите иметь возможность управлять своей программой из другой Java-программы в рамках одной JVM.

Используйте System.exit, если вы хотите полностью закрыть полную JVM, и если вы хотите воспользоваться возможностями, описанными в других ответах (например, при отключении крючков: Java shutdown hook, ненулевое возвращаемое значение для вызовов командной строки: Как получить статус выхода программы Java в пакетном файле Windows).

Также посмотрите на исключения Runtime: System.exit(num) или выведите исключение RuntimeException из основного?