38 votes

tandis que (vrai); la boucle jette du code inaccessible quand elle n'est pas dans un vide

Je faisais quelques petits programmes en java. Je sais que si j'écris while(true); le programme va geler dans cette boucle. Si le code est comme ça:

Test 1:

public class While {
    public static void main(String[] args) {
        System.out.println("start");
        while (true);
        System.out.println("end");
    }
}

Le compilateur me lance le message d'erreur:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Unreachable code
    at While.main(While.java:6)

Je ne savais pas que cette erreur existe. Mais j'ai pourquoi il est jeté. Bien sûr, la ligne 6 a été inaccessible, provoquant un problème de compilation. Puis je l'ai testé ceci:

Test 2:

public class While {
    public static void main(String[] args) {
        System.out.println("start");
        a();
        b();
    }
    static void a() {
        while(true);
    }
    static void b() {
        System.out.println("end");
    }
}

Pour certaines raisons le programme s'est déroulé normalement (La console imprimé "démarrer" puis gelé). Le compilateur n'a pas pu vérifier à l'intérieur de l' void a() et de voir qu'il n'est pas joignable. Pour être sûr que j'ai essayé:

Test 3:

public class While {
    public static void main(String[] args) {
        System.out.println("start");
        a();
        System.out.println("end");
    }
    static void a() {
        while(true);
    }
}

Même résultat que le Test 2.

Après quelques recherches, j'ai trouvé cette question. Donc, si le code à l'intérieur des parenthèses est une variable, le compilateur ne jetez pas l'exception. Cela fait sens, mais je ne pense pas que la même chose s'applique voids.

Q: pourquoi le compilateur juste de me jeter à l'erreur au Test 1, si void b() (Test 2) et System.out.println("end"); (Test 3) n'est pas joignable?

EDIT: j'ai essayé de Test 1 en C++:

#include <iostream>

using namespace std;

int main()
{
    cout << "start" << endl;
    while(true);
    cout << "end" << endl;
    return 0;
}

Le compilateur n'a pas de jeter des erreurs, puis j'ai obtenu le même résultat que le Test 2 et 3. Test de Donc je suppose que c'est une java chose?

20voto

Thilo Points 108673

La langue spec a une définition exacte de ce que le compilateur doit traiter comme code inaccessible, voir aussi http://stackoverflow.com/a/20922409/14955.

En particulier, il ne se soucie pas si une méthode est terminée, et il n'a pas l'air à l'intérieur d'autres méthodes.

Il ne le fera pas plus que ça.

Cependant, vous pourriez obtenir de l'analyse de code statique des outils comme FindBugs pour obtenir un "plus" de l'analyse (pas sûr si ils détectent le modèle que vous avez décrit, mais, soit, et, comme cela a été souligné par d'autres, le problème de l'arrêt en toute généralité ne peut être algorithmiquement résolu de toute façon, si on doit tracer la ligne à certains raisonnablement définition de "best effort").

12voto

Mysticial Points 180300

En général, il n'est pas possible de déterminer avec une absolue certainement si oui ou non quelque chose est accessible.

Pourquoi? C'est l'équivalent du Problème de l'Arrêt.

Le problème de l'arrêt, il demande:

Donné une description de l'arbitraire d'un programme d'ordinateur, de décider si le programme se termine en cours d'exécution ou continue à courir pour toujours.

Ce problème a été prouvée pour être insoluble.


Si oui ou non X morceau de code est accessible est la même chose que de dire que le code avant qu'il s'arrête.

Parce que c'est un problème insoluble, le compilateur (en Java ou tout autre langage) n'essayez pas très difficile à résoudre. Si elle arrive à déterminer que c'est vraiment inaccessible, alors vous obtenez le message d'avertissement. Si pas, il peut ou peut ne pas être accessible.

En Java, code inaccessible est une erreur du compilateur. Afin de maintenir la compatibilité, la langue spec définit exactement "comment dur", le compilateur devrait essayer. (Qui, selon les autres réponses, est "ne pas aller à l'intérieur d'une autre fonction".)

Dans d'autres langages (comme C++), le compilateur peut aller plus loin l'objet d'optimisations. (Code inaccessible peut être détectée après l'alignement de la fonction et de découvrir que il ne revient jamais.)

12voto

Qix Points 2787

Code inaccessible est une erreur de compilation qui dit simplement "le flux de ce programme n'a pas de sens, quelque chose ne sera jamais atteint".

Evidemment, vos tests de réaliser comment ils le font en raison d'une boucle sans fin, mais pourquoi la première échouer avec une erreur de compilation?

Une instruction while peut se terminer normalement si au moins l'un des suivantes est remplie:

  • L'instruction while est accessible et l'expression de condition n'est pas une expression constante (§15.28) avec la valeur true.

  • Il est accessible instruction break qui sort de l'instruction while.

D'accord, mais ce que sur les méthodes, les invocations (comme a()) - pourquoi faire des tests 2 et 3 compiler avec succès?

  • Une expression instruction peut se terminer normalement si elle est accessible.

Depuis une invocation de méthode est considérée comme une expression, ils vont toujours être accessible , tant que avant il bloque son chemin de la logique d'exécution.


Pour mieux illustrer certains raisonnement derrière ce mécanisme de compilation, nous allons prendre un if déclaration, par exemple.

if(false)
   System.out.println("Hello!"); // Never executes

Le ci-dessus sont correctes au moment de la compilation (bien que de nombreux IDE sera certainement pleurnicher!).

La Java 1.7 Spécification en parle:

La justification de cette différence de traitement est de permettre aux programmeurs de définir le "drapeau variables" tels que:

static final boolean DEBUG = false;

et ensuite écrire le code comme:

if (DEBUG) { x=3; }

L'idée est qu'il doit être possible de changer la valeur de DÉBOGAGE à partir de la valeur false à true ou de true à false et puis compiler le code correctement, sans autres modifications au texte du programme.

De plus, il est en fait une rétro-compatibilité raison:

Cette capacité à "conditionnellement de la compilation" a un impact significatif sur l', et de la relation, la compatibilité binaire (§13). Si un ensemble de classes que l'utilisation d'une telle "drapeau" variable sont compilés et à la condition que le code est omis, il ne suffit pas tard distribuer une nouvelle version de la classe ou de l'interface qui contient la définition de l'indicateur. Un changement de la valeur d'un indicateur n'est donc pas compatible binaire avec pré-existantes des fichiers binaires (§13.4.9). (Il y a d'autres raisons pour une telle incompatibilité, comme l'utilisation de constantes dans les cas les étiquettes dans les instructions de commutation; voir §13.4.9.)


La plupart (selon les spécifications), si pas tous, les implémentations de le compilateur Java ne pas traverser dans les méthodes. Lors de l'analyse de votre code Java lui-même, il voit a() comme juste un MethodInvocationElement, qui signifie 'Ce code appelle un autre code. Je n'aime pas vraiment, je suis juste à la recherche à la syntaxe.'. Du point de vue syntaxique, il est logique pour la suite le code d'appartenir après un appel à l' a().

Gardez à l'esprit les coûts de l'exécution. Compilation déjà prend une quantité considérable de temps. Afin de garder les choses rapidement, le compilateur Java ne fait pas de manière récursive sur les méthodes; cela prendrait des lustres (le compilateur aurait à évaluer de nombreux, de nombreux sentiers de code, en théorie).


Pour de plus amples répéter que c'est un point de vue syntaxique chassés, c'est pour ajouter un return; déclaration directement après votre boucle en a(). Ne compile pas, n'est ce pas? Du point de vue syntaxique, si, il a de sens sans elle.

6voto

Sotirios Delimanolis Points 77933

La réponse se trouve dans les règles définies pour l'accessibilité par le Langage Java Spécification. Il précise d'abord

C'est une erreur de compilation si un énoncé ne peut pas être exécutée parce qu'elle est inaccessible.

Et puis

Un while déclaration peut se terminer normalement le forum au moins une des suivantes est remplie:

  • L' while déclaration est accessible et l'expression de condition n'est pas une expression constante (§15.28) avec la valeur true.
  • Il est joignable break déclaration qui sort de l'instruction while.

et

Une expression instruction peut se terminer normalement ssi il est accessible.

Dans ton premier exemple, vous avez une boucle while qui ne peut pas se terminer normalement parce qu'il a une condition est une expression constante avec la valeur true et il n'est pas joignable break sein.

Dans votre deuxième et troisième exemples, l' expression de l'énoncé (method invocation) est accessible et peut donc se terminer normalement.


Donc je suppose que c'est une java chose?

Les règles ci-dessus sont Java règles. C++ a probablement ses propres règles, comme le font d'autres langues.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X