web-dev-qa-db-fra.com

Quand devrions-nous appeler System.exit dans Java

En Java, quelle est la différence avec ou sans System.exit(0) dans le code suivant?

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? 
    }      
}

Le document dit: "Cette méthode ne retourne jamais normalement." Qu'est-ce que ça veut dire?

184
pierrotlefou

System.exit() peut être utilisé pour exécuter crochets d'arrêt avant la fermeture du programme. C'est un moyen pratique de gérer les arrêts dans les grands programmes, où toutes les parties du programme ne peuvent pas (et ne devraient pas) être conscientes les unes des autres. Ensuite, si quelqu'un veut quitter, il peut simplement appeler System.exit() et les crochets d'arrêt (s'ils sont correctement configurés) s'occupent de toutes les cérémonies d'arrêt nécessaires, telles que la fermeture de fichiers, la libération de ressources, etc.

"Cette méthode ne retourne jamais normalement." signifie simplement que la méthode ne reviendra pas; une fois qu'un fil y passe, il ne reviendra pas.

Un autre moyen, peut-être plus courant, de quitter un programme consiste simplement à atteindre la fin de la méthode main. Mais si des threads non-démon sont en cours d'exécution, ils ne seront pas arrêtés et donc la machine virtuelle Java ne se fermera pas. Ainsi, si vous avez de tels threads non démon, vous avez besoin d'autres moyens (que les crochets d'arrêt) pour arrêter tous les threads non démon et libérer d'autres ressources. S'il n'y a pas d'autres threads non démon, le retour de main arrêtera la machine virtuelle Java et appellera les points d'ancrage.

Pour certaines raisons, les crochets d'arrêt semblent être un mécanisme sous-estimé et incompris, et les gens réinventent la roue avec toutes sortes de piratages personnalisés pour arrêter leurs programmes. Je vous encourage à utiliser des crochets d'arrêt. tout est là dans le standard Runtime que vous utiliserez quand même.

197
Joonas Pulakka

Dans ce cas, ce n'est pas nécessaire. Aucun thread supplémentaire n'a été démarré, vous ne modifiez pas le code de sortie (dont la valeur par défaut est 0) - en gros, cela ne sert à rien.

Lorsque la documentation dit que la méthode ne retourne jamais normalement, cela signifie que la ligne de code suivante est effectivement inaccessible, même si le compilateur ne sait pas que:

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

Soit une exception sera levée, soit le VM se terminera avant de revenir. Il ne sera jamais "juste revenir".

Il est très rare d’être utile d’appeler System.exit() IME. Cela peut avoir un sens si vous écrivez un outil en ligne de commande et que vous voulez indiquer une erreur via le code de sortie plutôt que de simplement lancer une exception ... mais je ne me souviens pas de la dernière fois que je l'ai utilisé dans un code de production normal. .

48
Jon Skeet

La méthode ne retourne jamais car c'est la fin du monde et aucun de votre code ne sera exécuté ensuite.

Votre application, dans votre exemple, se terminerait quand même au même endroit dans le code, mais si vous utilisez System.exit. vous avez la possibilité de retourner un code personnalisé à l'environnement, comme par exemple

System.exit(42);

Qui va utiliser votre code de sortie? Un script qui appelle l'application. Fonctionne sous Windows, Unix et tous les autres environnements de script.

Pourquoi retourner un code? Pour dire des choses comme "je n'ai pas réussi", "la base de données n'a pas répondu".

Pour voir comment obtenir la valeur od un code de sortie et l'utiliser dans un script Shell unix ou Windows, vous pouvez vérifier cette réponse sur ce site

15
mico

System.exit(0) termine la machine virtuelle. Dans des exemples simples comme celui-ci, il est difficile de percevoir la différence. Le paramètre est renvoyé au système d’exploitation et est normalement utilisé pour signaler une fin anormale (erreur fatale, par exemple). Par conséquent, si vous appelez Java à partir d’un fichier de commandes ou d’un script Shell, vous pourrez obtenir cette valeur et avoir une idée si l'application a réussi.

Cela aurait un impact considérable si vous appeliez System.exit(0) sur une application déployée sur un serveur d'applications (réfléchissez-y avant de l'essayer).

14
Qwerky

Dans les applications pouvant comporter des points d'arrêt complexes, cette méthode ne doit pas être appelée à partir d'un thread inconnu. System.exit ne se ferme jamais normalement car l'appel sera bloqué jusqu'à ce que la machine virtuelle Java soit terminée. C'est comme si le code en cours d'exécution était branché avant de pouvoir être terminé. L'appel de System.exit lancera les crochets d'arrêt du programme et tout fil qui appelle System.exit sera bloqué jusqu'à la fin du programme. Cela implique que si le crochet d'arrêt soumet à son tour une tâche au thread à partir duquel System.exit a été appelé, le programme se bloquera.

Je gère cela dans mon code avec les éléments suivants:

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

On ne devrait JAMAIS appeler System.exit(0) pour ces raisons:

  1. C'est un "goto" caché et un "gotos" brise le flux de contrôle. S'appuyer sur des points d'ancrage dans ce contexte est une cartographie mentale que chaque développeur de l'équipe doit connaître.
  2. Quitter le programme "normalement" fournit le même code de sortie au système d'exploitation que System.exit(0), de sorte qu'il est redondant.

    Si votre programme ne peut pas quitter "normalement", vous avez perdu le contrôle de votre développement [conception]. Vous devriez toujours avoir le plein contrôle de l'état du système.

  3. Les problèmes de programmation tels que l'exécution de threads qui ne sont pas arrêtés normalement sont masqués.
  4. Vous pouvez rencontrer un état d'application incohérent interrompant les threads de manière anormale. (Reportez-vous à # 3)

Soit dit en passant: Il est logique de renvoyer des codes retour autres que 0 si vous souhaitez indiquer une fin de programme anormale.

7
oopexpert

Bien que la réponse ait été vraiment utile, mais que certains détails manquaient encore. J'espère que ci-dessous aidera à comprendre le processus d'arrêt en Java, en plus de la réponse ci-dessus:

  1. Lors d'un arrêt ordonné *, la machine virtuelle Java démarre d'abord tous les points d'arrêt enregistrés. Les crochets d'arrêt sont des threads non démarrés qui sont enregistrés avec Runtime.addShutdownHook.
  2. La machine virtuelle Java ne donne aucune garantie sur l'ordre dans lequel les points d'arrêt sont démarrés. Si des threads d'application (démon ou nondaemon) sont toujours en cours d'exécution au moment de l'arrêt, ils continuent de s'exécuter simultanément avec le processus d'arrêt.
  3. Une fois tous les points d'arrêt terminés, la machine virtuelle Java peut choisir d'exécuter les finaliseurs si runFinalizersOnExit est true, puis s'arrête.
  4. La JVM n'essaie pas d'arrêter ni d'interrompre les threads d'application qui sont encore en cours d'exécution au moment de l'arrêt. ils sont brusquement arrêtés lorsque la JVM s’arrête finalement.
  5. Si les points d'arrêt ou les finaliseurs ne se terminent pas, le processus d'arrêt ordonné se bloque et la machine virtuelle Java doit être arrêtée brutalement.
  6. Lors d’un arrêt brutal, la machine virtuelle Java n’est tenue de rien d’arrêter la machine virtuelle; les crochets d'arrêt ne fonctionneront pas.

PS: La machine virtuelle Java peut s’arrêter de manière ordonnée ou abrupte.

  1. Un arrêt ordonné est lancé lorsque le dernier thread "normal" (nondaemon) se termine, quelqu'un appelle System.exit ou par un autre moyen spécifique à la plate-forme (tel que l'envoi d'un SIGINT ou la frappe de Ctrl-C).
  2. Tandis que ci-dessus est le moyen standard et préféré pour la machine virtuelle d’arrêter, vous pouvez également la fermer brutalement en appelant Runtime.halt ou en supprimant le processus de la machine virtuelle via le système d’exploitation (par exemple, en envoyant un SIGKILL).
7
Mohit

System.exit est nécessaire

  • lorsque vous souhaitez renvoyer un code d'erreur autre que 0
  • quand vous voulez quitter votre programme depuis un endroit qui n'est pas main ()

Dans votre cas, il fait exactement la même chose que le simple renvoi du principal.

5
mfx

Spécification du langage Java dit que

Sortie du programme

Un programme termine toute son activité et se termine lorsque l’une des deux choses suivantes se produit:

Tous les threads qui ne sont pas des démons se terminent.

Certains threads appellent la méthode de sortie de la classe Runtime ou de la classe System , et l'opération de sortie n'est pas interdite par le gestionnaire de sécurité.

Cela signifie que vous devriez l'utiliser quand vous avez un gros programme (enfin, au moins plus gros que celui-ci) et que vous voulez terminer son exécution.

4
Marcin Szymczak

Si vous utilisez un autre programme dans la machine virtuelle Java et que vous utilisez System.exit, ce deuxième programme sera également fermé. Imaginons par exemple que vous exécutiez un travail Java sur un nœud de cluster et que le programme Java qui gère le nœud de cluster s'exécute dans la même machine virtuelle. Si le travail utilisait System.exit, il le fermerait non seulement, mais également "arrêterait le noeud complet". Vous ne pourrez pas envoyer d'autre travail à ce nœud de cluster car le programme de gestion a été fermé accidentellement.

Par conséquent, n'utilisez pas System.exit si vous souhaitez pouvoir contrôler votre programme à partir d'un autre programme Java de la même machine virtuelle.

Utilisez System.exit si vous souhaitez fermer l'intégralité de la machine virtuelle Java à dessein et si vous souhaitez tirer parti des possibilités décrites dans les autres réponses (par exemple, points d'arrêt à la fermeture: point d'arrêt à l'exécution de Java , non -zero renvoie la valeur pour les appels en ligne de commande: Comment obtenir l'état de sortie d'un programme Java dans un fichier de traitement par lots Windows ).

Jetez également un coup d’œil aux exceptions d’exécution: System.exit (num) ou lève une exception RuntimeException depuis main?

3
Stefan