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


Je faisais de 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 jette l'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 compris pourquoi c'est jeté. Bien sûr, la ligne 6 était inaccessible, provoquant un problème de compilation. Puis j'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 a fonctionné normalement (La console a imprimé "start" puis s'est figée). Le compilateur n'a pas pu vérifier à l'intérieur de void a() et voir qu'il n'est pas accessible. Pour être sûr d'avoir 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 Test 2.

Après quelques recherches j'ai trouvé ça question. Donc, si le code entre parenthèses est une variable, le compilateur ne lançera pas l'exception. Cela a du sens, mais je ne pense pas que la même chose s'applique à voids.

Q: Alors, pourquoi le compilateur me lance-t-il l'erreur au test 1, si void b() (Test 2) et System.out.println("end"); (Test 3) n'est pas accessible?

MODIFIER: J'ai essayé le 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 commis aucune erreur, alors j'ai eu le même résultat que le test 2 et le test 3. Donc je suppose que c'est une chose java?


38
2018-06-09 23:04


origine


Réponses:


le Spécification de langue a une définition exacte ce que le compilateur doit traiter comme du code inaccessible, voir aussi https://stackoverflow.com/a/20922409/14955.

En particulier, il ne se soucie pas de savoir si une méthode se termine et elle ne regarde pas à l'intérieur d'autres méthodes.

Cela ne fera pas plus que ça.

Cependant, vous pouvez obtenir des outils d’analyse de code statique tels que FindBugs pour obtenir une analyse plus approfondie (vous ne savez pas non plus s'ils détectent le modèle que vous avez décrit et, comme d’autres l’ont fait remarquer, le problème être résolus de façon algorithmique de toute façon, il faut donc tracer la ligne à une définition raisonnable du "meilleur effort").


20
2018-06-09 23:10



En général, il est impossible de déterminer avec certitude si quelque chose est accessible ou non.

Pourquoi? C'est l'équivalent de la Arrêter le problème.

Le problème en suspens demande:

Après avoir décrit un programme informatique arbitraire, décidez si le programme se termine ou continue à fonctionner indéfiniment.

Ce problème s'est avéré insoluble.


Que le code soit ou non accessible est le même que de dire si le code doit s’arrêter.

Comme il s’agit d’un problème insoluble, le compilateur (en Java ou dans tout autre langage) ne s’efforce pas de le résoudre. Si cela arrive à déterminer que c'est vraiment inaccessible, alors vous obtenez l'avertissement. Sinon, il peut ou peut ne pas être accessible.

En Java, le code inaccessible est une erreur de compilation. Donc, afin de maintenir la compatibilité, la spécification du langage définit exactement "à quel point" le compilateur doit essayer. (Ce qui, selon les autres réponses, est "ne pas entrer dans une autre fonction".)

Dans d'autres langages (tels que C ++), le compilateur peut être soumis à des optimisations. (Un code inaccessible peut être détecté après avoir inséré la fonction et découvert qu’elle ne revient jamais.)


12
2018-06-09 23:12



Code inaccessible est une erreur de compilation qui dit simplement «le déroulement de ce programme n'a pas de sens; quelque chose ne sera jamais atteint '.

Évidemment, vos tests fonctionnent comme ils le font grâce à une boucle sans fin, mais pourquoi le premier échoue avec une erreur de compilation?

Une déclaration while peut se terminer normalement si au moins un des   suivant est vrai:

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

  • Il existe une instruction de rupture accessible qui quitte l'instruction while.

Bon, mais qu'en est-il des invocations de méthodes (telles que a()) - pourquoi les tests 2 et 3 réussissent-ils à compiler?

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

Une invocation de méthode étant considérée comme une expression, elles seront toujours être joignable tant que rien avant qu'il ne bloque son chemin d'exécution logique.


Pour mieux illustrer certains raisonnements derrière ce mécanisme de compilation, prenons une if déclaration, par exemple.

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

Ce qui précède sera correct au moment de la compilation (bien que de nombreux IDE vont certainement gémir!).

La spécification Java 1.7 en parle:

La raison de ce traitement différent est de permettre aux programmeurs de   définir "variables de drapeau" telles que:

static final boolean DEBUG = false;

puis écrivez un code tel que:

if (DEBUG) { x=3; }

L’idée est qu’il devrait être possible de changer   la valeur de DEBUG de faux à vrai ou de vrai à faux et ensuite   compiler le code correctement sans autres modifications au texte du programme.

De plus, il y a réellement une raison de compatibilité ascendante également:

Cette capacité à "compiler sous condition" a un impact significatif sur,   et relation à la compatibilité binaire (§13). Si un ensemble de classes   qui utilisent une telle variable "flag" sont compilées et le code conditionnel est   omis, il ne suffit plus de distribuer ultérieurement une nouvelle version de   la classe ou l'interface qui contient la définition du drapeau. UNE   changer la valeur d'un drapeau n'est donc pas compatible binaire   avec des binaires préexistants (§13.4.9). (Il y a d'autres raisons pour   cette incompatibilité aussi bien, comme l'utilisation de constantes dans le cas   étiquettes dans les instructions de commutation; voir §13.4.9.)


La plupart (selon les spécifications), sinon toutes les implémentations du compilateur Java font ne pas traverser en méthodes. Lors de l'analyse de votre code Java lui-même, il voit a() comme juste un MethodInvocationElement, sens 'Ce code appelle un autre code. Je m'en fiche vraiment, je ne fais que regarder la syntaxe.. Syntactiquement, il est logique que le code suivant apparaisse après un appel à a().

Gardez à l'esprit les coûts de performance. La compilation prend déjà beaucoup de temps. Afin de garder les choses rapides, le compilateur Java ne recycle pas réellement dans les méthodes; cela prendrait du temps (le compilateur devrait évaluer plusieurs chemins de code en théorie).


Pour réitérer que c'est syntaxiquement conduit à ajouter un return; déclaration directement après votre boucle dans a(). Ne compile pas, n'est-ce pas? Syntactiquementcependant, cela a du sens sans elle.


12
2018-06-09 23:13



La réponse réside dans les règles énoncées pour accessibilité par le Spécification du langage Java. Il commence par affirmer

C'est une erreur de compilation si une instruction ne peut pas être exécutée car elle est inaccessible.

Et alors

UNE while déclaration peut compléter normalement si et au moins l'un des   suivant est vrai:

  • le while l'instruction est accessible et l'expression de condition n'est pas une expression constante (§15.28) avec une valeur true.
  • Il y a un accessible break déclaration qui quitte l'instruction while.

et

Une expression peut être complétée normalement si elle est accessible.

Dans votre premier exemple, vous avez une boucle while qui ne peut pas se terminer normalement car elle a une condition qui est une expression constante avec une valeur true et il n'y a pas de joignable break à l'intérieur.

Dans vos deuxième et troisième exemples, le déclaration d'expression (invocation de méthode) est accessible et peut donc se terminer normalement.


Donc je suppose que c'est une chose java?

Les règles ci-dessus sont les règles de Java. C ++ a probablement ses propres règles, comme d'autres langages.


6
2018-06-09 23:12