53 votes

Erreur de code inaccessible vs avertissement de code mort en Java sous Eclipse?

Personne ne sait pourquoi:

public void foo()
{
    System.out.println("Hello");
    return;
    System.out.println("World!");
}

Serait inscrit comme un "inaccessible erreur" sous Eclipse, mais

public void foo()
{
    System.out.println("Hello");
    if(true) return;
    System.out.println("World!");
}

Seulement déclenche un "code Mort" avertissement?

La seule explication que je peux penser, c'est que le compilateur Java uniquement des drapeaux de la première, et que certains d'analyse supplémentaires dans Eclipse chiffres la deuxième. Cependant, si c'est le cas, pourquoi ne peut pas le compilateur Java figure cette affaire au moment de la compilation?

Ne serait pas le compilateur Java figure out au moment de la compilation que le si(vrai) n'a aucun effet, ce qui donne du bytecode qui est essentiellement identique? À quel point est accessible d'analyse de code appliquée?

Je suppose que d'une manière plus générale à réfléchir à cette question est: "quand est accessible d'analyse de code appliquée"? Dans la transformation de la deuxième fragment de code Java pour la finale du bytecode, je suis sûr qu'à un certain point le "if(true)" runtime équivalent est supprimé, et les représentations de ces deux programmes deviennent identiques. Ne serait pas le compilateur Java puis appliquer ses accessible de l'analyse de code à nouveau?

34voto

BalusC Points 498232

Le premier ne veut pas compiler (vous avez une erreur), la seconde compile (vous venez de recevoir un message d'avertissement). C'est toute la différence.

Pourquoi Eclipse détecte code mort, eh bien, c'est juste de la commodité d'un développement intégré de l'outil avec un compilateur intégré qui peut être réglé plus plutôt que de JDK pour détecter ce genre de code.

Mise à jour: le JDK effectivement élimine du code mort.

public class Test {
    public void foo() {
        System.out.println("foo");
        if(true)return;
        System.out.println("foo");
    }
    public void bar() {
        System.out.println("bar");
        if(false)return;
        System.out.println("bar");
    }
}

javap -c dit:

public class Test extends java.lang.Objet{
public Test();
Code:
 0: aload_0
 1: invokespecial #1; //Méthode java/lang/Object."":()V
 4: retour

public void foo();
Code:
 0: getstatic #2; //le Champ java/lang/Système.out:Ljava/io/PrintStream;
 3: pma #3; //la Chaîne foo
 5: invokevirtual #4; //Méthode java/io/PrintStream.println:(Ljava/lang/StrV
 8: retour

public void bar();
Code:
 0: getstatic #2; //le Champ java/lang/Système.out:Ljava/io/PrintStream;
 3: pma #5; //Chaîne de bar
 5: invokevirtual #4; //Méthode java/io/PrintStream.println:(Ljava/lang/String;)V
 8: getstatic #2; //le Champ java/lang/Système.out:Ljava/io/PrintStream;
 11: pma #5; //Chaîne de bar
 13: invokevirtual #4; //Méthode java/io/PrintStream.println:(Ljava/lang/String;)V
 16: le retour

}

Pourquoi il (le Soleil) n'est pas de donner un avertissement à ce sujet, je n'ai aucune idée :) Au moins le JDK compilateur a fait DCE (Élimination du Code Mort) builtin.

25voto

Paul Wagland Points 10487

Code inaccessible est une erreur, selon le Langage Java Spec.

Pour citer le JLS:

L'idée est qu'il doit y avoir un chemin d'exécution depuis le début de l'constructeur, une méthode, un exemple de l'initialiseur ou d'initialiseur statique qui contient la déclaration de la déclaration elle-même. L'analyse tient compte de la structure des énoncés. Sauf que pour le traitement de tout, faire, et pour les états dont l'état de santé de l'expression a la valeur de la constante true, les valeurs des expressions ne sont pas prises en compte dans l'analyse des flux.

Ce que cela signifie, c'est que l' if bloc n'est pas pris en compte, car si vous passez par l'un des chemins de l' if instruction, vous pouvez arriver en final instruction print. Si vous avez modifié votre code:

public void foo() {
    System.out.println("Hello");
    if (true)
        return;
    else
        return;
    System.out.println("World!");
}

puis, soudain, il ne compile pas plus, car il n'y a pas de chemin par le biais de l' if déclaration qui permettrait à la dernière ligne pour être atteint.

C'est une application conforme compilateur n'est pas autorisé à compiler votre premier fragment de code. Pour de plus amples citer le JLS:

Par exemple, la déclaration suivante des résultats dans une erreur de compilation:

while (false) { x=3; }

parce que l'instruction x=3; est pas accessible; mais la superficiellement cas similaire:

if (false) { x=3; }

n'entraîne pas une erreur de compilation. Un compilateur optimisant peut se rendre compte que l'instruction x=3; ne sera jamais exécutée et peut choisir d'omettre le code pour que la déclaration de la classe générée fichier, mais l'instruction x=3; n'est pas considéré comme "inaccessible" dans le sens technique spécifiée ici.

Le deuxième avertissement que Eclipse donne, à propos de code mort, est un avertissement généré par le compilateur, qui n'est pas "inaccessible", selon le JLS, mais dans la pratique. C'est l'une des peluches style de vérifier que Eclipse fournit. C'est totalement facultatif, et, à l'aide de la configuration Eclipse, peut être désactivé, ou transformé en une erreur de compilation au lieu d'un avertissement.

Ce second bloc est une "odeur de code", if (false) des blocs sont en règle générale mis à désactiver le code à des fins de débogage, de l'avoir laissé derrière est généralement accidentelle, et donc l'avertissement.

En fait, Eclipse n'est même plus avancé des tests pour déterminer les valeurs possibles d'une instruction if pour déterminer si oui ou non il est possible de prendre deux chemins. Par exemple, Eclipse serait se plaignent aussi de la mort de code dans la méthode suivante:

public void foo() {
    System.out.println("Hello");
    boolean bool = Random.nextBoolean();
    if (bool)
        return;
    if (bool || Random.nextBoolean())
      System.out.println("World!");
}

Il va générer un code inaccessible pour la seconde si l'instruction, car il peut raison qu' bool ne doivent l'être qu' false à ce point dans le code. Dans un court fragment de code, il est évident que les deux si les déclarations sont tester la même chose, mais si il y a 10-15 lignes de code dans le milieu, il pourrait ne pas être si évident plus.

Donc en résumé, la différence entre les deux: l'un est interdit par la JLS, et l'un ne l'est pas, mais est détecté par Eclipse en tant que service pour le programmeur.

14voto

Carlos Heuberger Points 11804

C'est pour permettre à une sorte de compilation conditionnelle.
Ce n'est pas une erreur avec if, mais le compilateur signalera une erreur pour while, do-while et for.
C'est OK:

if (true) return;    // or false
System.out.println("doing something");

Ce sont des erreurs

while (true) {
}
System.out.println("unreachable");

while (false) {
    System.out.println("unreachable");
}

do {
    System.out.println("unreachable");
} while (true);

for(;;) {
}
System.out.println("unreachable");

Il est expliqué à la fin de JLS 14.21: Inaccessible Déclarations:

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 ensuite compiler le code correctement, sans autres modifications au texte du programme.

2voto

Carl Smotricz Points 36400

L' if (true) est un peu plus subtil que "inaccessible", parce que codée en dur return , ce sera toujours le code suivant inaccessible, mais l'évolution de la condition de l' if pourrait faire la déclaration suivante accessible.

Avoir un conditionnel, il signifie qu'il y a une chance condition pourrait changer. Il y a des cas où quelque chose de plus compliqué qu'un true est dans les parenthèses, et il n'est pas évident pour le lecteur humain que le code suivant est "endormi", mais le compilateur avis, il est donc en mesure de vous avertir à ce sujet.

Eclipse est mentionné ici, et il rend les choses semblent un peu plus compliqué pour l'utilisateur, mais en réalité, sous Eclipse est juste un (très sophistiqués) le compilateur Java qui se passe à la fonction de beaucoup de commutateurs pour les avertissements etc. cette Éclipse peut allumer et éteindre. En d'autres termes, vous n'obtenez pas tout à fait l'ampleur de différents avertissements/erreurs à partir d'une quinte javac de la compilation, ni avez-vous un moyen pratique pour convertir tout ou de les désactiver. Mais c'est la même chose, juste avec plus de cloches et de sifflets.

2voto

Yishai Points 42417

Je pense que d'une manière pour certains, c'est que code inaccessible est plus probable qu'une erreur, et l'JLS essaie de vous protéger contre de telles erreurs.

Permettant if (true) return; est un bon moyen de contourner la JLS limitation, si vous voulez vraiment le faire exprès. Si le JLS arrêté, ce serait de prendre le chemin. En outre, il faut aussi arrêter:

 public static boolean DEBUG = true; //In some global class somewhere else


 ...

 if (DEBUG) return; //in a completely unrelated class.

 ...

Parce que le DÉBOGAGE constante est entièrement doublée, et fonctionnellement équivalent, juste en tapant un vrai que si la condition. À partir d'une JLS perspective ces deux cas sont très similaires.

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