Unerreichbarer Codefehler vs. Tote Code-Warnung in Java unter Eclipse?

Lesezeit: 10 Minuten

Unerreichbarer Codefehler vs Tote Code Warnung in Java unter Eclipse
Uri

Weiß jemand warum:

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

Würde unter Eclipse als “unerreichbarer Fehler” gemeldet, aber

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

Löst nur eine “Dead code”-Warnung aus?

Die einzige Erklärung, die mir einfällt, ist, dass der Java-Compiler nur den ersten markiert und dass eine zusätzliche Analyse in Eclipse den zweiten herausfindet. Wenn dies jedoch der Fall ist, warum kann der Java-Compiler diesen Fall zur Kompilierzeit nicht herausfinden?

Würde der Java-Compiler zur Kompilierzeit nicht herausfinden, dass if(true) keine Auswirkung hat und somit Bytecode ergibt, der im Wesentlichen identisch ist? An welcher Stelle wird die Erreichbare-Code-Analyse angewendet?

Ich denke, eine allgemeinere Art, sich diese Frage zu stellen, ist: “Wann wird die Analyse des erreichbaren Codes angewendet”? Bei der Transformation des zweiten Java-Codefragments zum endgültigen Bytecode bin ich mir sicher, dass irgendwann das Laufzeitäquivalent “if(true)” entfernt wird und die Darstellungen der beiden Programme identisch werden. Würde der Java-Compiler dann nicht erneut seine Erreichbarkeitscode-Analyse anwenden?

Unerreichbarer Codefehler vs Tote Code Warnung in Java unter Eclipse
BalusC

Der erste tut nicht kompilieren (Sie haben einen Fehler erhalten), die zweite kompiliert (Sie haben gerade eine Warnung erhalten). Das ist der Unterschied.

Der Grund, warum Eclipse toten Code erkennt, ist nur die Bequemlichkeit eines integrierten Entwicklungstools mit einem integrierten Compiler, der im Gegensatz zu JDK feiner abgestimmt werden kann, um diese Art von Code zu erkennen.

Aktualisieren: Das JDK eliminiert eigentlich toten Code.

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 sagt:

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public void foo();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #3; //String foo
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/StrV
   8:   return

public void bar();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #5; //String bar
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  ldc             #5; //String bar
   13:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   16:  return

}

Warum es (Sun) keine Warnung davor ausgibt, habe ich keine Ahnung 🙂 Zumindest der JDK-Compiler hat tatsächlich DCE (Dead Code Elimination) eingebaut.

  • Aber warum würde der Java-Compiler das if(true) nicht zur Kompilierzeit beseitigen und den Fehler dann identifizieren, wenn er erreichbaren Code analysiert?

    – Uri

    26. Januar ’10 um 17:08


  • Hey Uri, du kannst “if(true)” durch “boolean x=true; if(x)” ersetzen. Es ist nicht die Aufgabe des Compilers, es zu beseitigen, da Sie beispielsweise einen Breakpoint setzen und den Wert von x während der Ausführung ändern können

    – Yoni

    26. Januar ’10 um 17:10

  • Hoffentlich wird meine Antwort (seit Sie sie zum ersten Mal gesehen haben, ein wenig bearbeitet) das etwas klarer machen.

    – Carl Smotricz

    26. Januar ’10 um 17:11

  • +1 Der Java-Compiler generiert keinen Bytecode für Blöcke, die nicht ausgeführt werden. Code wird weiterhin generiert, wenn ein Ausdruck zur Laufzeit als falsch ausgewertet wird. Bytecode wird nur dann nicht erzeugt, wenn der Ausdruck zur Kompilierzeit auf false ausgewertet wird. Zumindest ist das mein Verständnis der Funktionsweise.

    – TschadNC

    26. Januar ’10 um 17:21


  • Die Spezifikation der Java-Sprache erlaubt speziell konstante if Ausdrücke, die zu ausgewertet werden true oder false als Mittel zum Ein- oder Ausschalten von Code, z. B. Debug- oder Diagnosecode, mit einem “Umlegen eines Schalters”. Die Ausdrücke if(true) und if(DEBUGS) fallen in diese Kategorie. Also weder Eclipse noch ein anderer Java-Compiler dürfen sie als Fehler zu behandeln. Darüber hinaus erfordert es insbesondere, dass ein solcher konstanter bewachter Code entfernt wird, wenn er als ausgewertet wird false.

    – Lawrence Dol

    21. November ’15 um 23:07


1641744915 774 Unerreichbarer Codefehler vs Tote Code Warnung in Java unter Eclipse
Paul Wagland

Unerreichbarer Code ist ein Fehler gemäß der Java-Sprachspezifikation.

Um aus der JLS zu zitieren:

Die Idee ist, dass es einen möglichen Ausführungspfad vom Anfang des Konstruktors, der Methode, des Instanzinitialisierers oder des statischen Initialisierers, der die Anweisung enthält, bis zur Anweisung selbst geben muss. Die Analyse berücksichtigt die Struktur von Aussagen. Abgesehen von der Sonderbehandlung von while, do und für Anweisungen, deren Bedingungsausdruck den konstanten Wert true hat, werden die Werte von Ausdrücken bei der Flussanalyse nicht berücksichtigt.

Das bedeutet, dass die if Block wird nicht berücksichtigt, da, wenn Sie einen der Pfade der if -Anweisung können Sie die endgültige Druckanweisung erreichen. Wenn Sie Ihren Code geändert haben in:

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

dann würde es plötzlich nicht mehr kompilieren, da es keinen Weg durch die gibt if -Anweisung, die es ermöglichen würde, die letzte Zeile zu erreichen.

Das heißt, ein Java-kompatibler Compiler darf Ihr erstes Codefragment nicht kompilieren. Um die JLS weiter zu zitieren:

Als Beispiel führt die folgende Anweisung zu einem Kompilierzeitfehler:

while (false) { x=3; }

weil die Aussage x=3; ist nicht erreichbar; aber der oberflächlich ähnliche Fall:

if (false) { x=3; }

führt nicht zu einem Kompilierzeitfehler. Ein optimierender Compiler kann erkennen, dass die Anweisung x=3; wird nie ausgeführt und kann den Code für diese Anweisung aus der generierten Klassendatei weglassen, aber die Anweisung x=3; gilt nicht als “unerreichbar” im hier genannten technischen Sinne.

Die zweite Warnung, die Eclipse über toten Code ausgibt, ist eine vom Compiler generierte Warnung, die laut JLS nicht “unerreichbar”, aber in der Praxis ist. Dies ist eine zusätzliche Fussel Stilprüfung, die Eclipse bereitstellt. Dies ist völlig optional und kann mithilfe der Eclipse-Konfiguration deaktiviert oder in einen Compilerfehler anstelle einer Warnung umgewandelt werden.

Dieser zweite Block ist ein “Code-Geruch”, if (false) Blöcke werden normalerweise eingefügt, um Code für Debugging-Zwecke zu deaktivieren, es ist normalerweise versehentlich, wenn es zurückgelassen wird, und daher die Warnung.

Tatsächlich führt Eclipse sogar noch komplexere Tests durch, um die möglichen Werte für eine if-Anweisung zu bestimmen, um zu bestimmen, ob beide Wege möglich sind oder nicht. Eclipse würde sich beispielsweise auch in der folgenden Methode über toten Code beschweren:

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

Es wird einen nicht erreichbaren Code für die zweite if-Anweisung generieren, da dies folgern kann bool muss nur sein false an dieser Stelle im Code. In einem so kurzen Codefragment ist es offensichtlich, dass die beiden if-Anweisungen dasselbe testen, aber wenn es 10-15 Codezeilen in der Mitte gibt, ist es möglicherweise nicht mehr so ​​offensichtlich.

Zusammenfassend also der Unterschied zwischen den beiden: Einer wird von JLS verboten und einer nicht, wird aber von Eclipse als Dienst für den Programmierer erkannt.

  • Interessant, dass sie ‘if’ nicht in die Liste der Kontrollflussanweisungen mit “Sonderbehandlung” aufgenommen haben. Ich wundere mich warum?

    – Verdienst

    26. Januar ’10 um 17:46

  • Oh, ich verstehe: Die Sonderbehandlung besteht darin, offensichtliche Endlosschleifen zu erkennen. ‘If’ ist keine Schleifenanweisung. (Ich bin heute etwas langsam…)

    – Verdienst

    26. Januar ’10 um 17:48

  • @meriton: Ich habe den entsprechenden Abschnitt aus der JLS hinzugefügt, um zu zeigen, was sie zu lösen versuchten.

    – Paul Wagland

    26. Januar ’10 um 18:24

  • der Zweite if vielleicht true als die Random.nextBoolean kann true zurückgeben. Vielleicht meintest du &&?

    – Mordechai

    25. Juni ’15 um 13:19

Unerreichbarer Codefehler vs Tote Code Warnung in Java unter Eclipse
Benutzer85421

Dies ist eine Art von bedingte Zusammenstellung.
Es ist kein Fehler mit if, aber der Compiler meldet einen Fehler für while, do-while und for.
Das ist in Ordnung:

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

Das sind Fehler

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

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

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

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

Es wird am Ende erklärt JLS 14.21: Unerreichbare Anweisungen:

Der Grund für diese unterschiedliche Behandlung besteht darin, Programmierern zu ermöglichen, “Flag-Variablen” zu definieren, wie zum Beispiel:

 static final boolean DEBUG = false;

und schreibe dann Code wie:

   if (DEBUG) { x=3; }

Die Idee ist, dass es möglich sein sollte, den Wert von DEBUG von false auf true oder von true auf false zu ändern und dann den Code ohne weitere Änderungen am Programmtext korrekt zu kompilieren.

  • +1 für die Begründung des Verhaltensunterschieds.

    – Thorkil Holm-Jacobsen

    2. März ’14 um 9:30

1641744915 332 Unerreichbarer Codefehler vs Tote Code Warnung in Java unter Eclipse
Carl Smotricz

Der if (true) ist etwas subtiler als “unerreichbar”; weil das hartcodiert return wird den folgenden Code immer unerreichbar machen, aber die Bedingung im ändern if könnte die folgende Aussage erreichbar machen.

Wenn eine Bedingung vorhanden ist, bedeutet dies, dass sich die Bedingung möglicherweise ändern kann. Es gibt Fälle, in denen etwas komplizierter ist als a true steht in Klammern, und es ist für den menschlichen Leser nicht offensichtlich, dass der folgende Code “deadened” ist, aber der Compiler bemerkt dies und kann Sie daher warnen.

Eclipse wird hier erwähnt, und es macht die Dinge für den Benutzer etwas komplizierter; aber eigentlich ist unter Eclipse nur ein (sehr ausgeklügelter) Java-Compiler, der zufällig viele Schalter für Warnungen usw. enthält, die Eclipse ein- und ausschalten kann. Mit anderen Worten, Sie erhalten nicht ganz die Breite der verschiedenen Warnungen/Fehler von einer Geraden javac kompilieren, noch haben Sie bequeme Mittel, um sie alle ein- oder auszuschalten. Aber es ist der gleiche Deal, nur mit mehr Schnickschnack.

Ich denke, eine Möglichkeit, es zu verbessern, besteht darin, dass nicht erreichbarer Code höchstwahrscheinlich ein Fehler ist und die JLS versucht, Sie vor solchen Fehlern zu schützen.

Zulassen if (true) return; ist eine gute Möglichkeit, die JLS-Beschränkung zu umgehen, wenn Sie dies tatsächlich absichtlich tun möchten. Wenn die JLS dies stoppen würde, würde es im Weg stehen. Außerdem sollte es auch aufhören:

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


 ...

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

 ...

Weil die DEBUG-Konstante vollständig inline eingebunden ist und funktionell äquivalent dazu ist, einfach true in dieser if-Bedingung einzugeben. Aus der Sicht von JLS sind diese beiden Fälle sehr ähnlich.

1641744915 354 Unerreichbarer Codefehler vs Tote Code Warnung in Java unter Eclipse
Yoni

Der Unterschied liegt in der Semantik zwischen Laufzeit und Kompilierzeit. In Ihrem zweiten Beispiel wird der Code in einen if-else-Zweig im Bytecode kompiliert, und Eclipse ist einfach schlau genug, um Ihnen mitzuteilen, dass der else-Teil zur Laufzeit nie erreicht wird. Eclipse warnt Sie nur, da es sich immer noch um Rechtskodex handelt.

In Ihrem ersten Beispiel handelt es sich um einen Fehler, da der Code nach der Definition von java illegal ist. Der Compiler erlaubt Ihnen nicht, Bytecode mit nicht erreichbaren Anweisungen zu erstellen.

1641744915 997 Unerreichbarer Codefehler vs Tote Code Warnung in Java unter Eclipse
Houcheng

Ich habe Eclipse ausprobiert und denke, dass es 3 Arten von totem Code gibt, mit denen JDK umgegangen wird: 1) keine Warnung, 2) Warnung und 3) Fehler.

Bei einem typischen bedingten “IF”-Kompilierungscode erkennt das JDK dies und meldet es nicht als toten Code. Bei einem toten Code, der durch ein konstantes boolesches Flag verursacht wird, erkennt das JDK dies und meldet es auf der Warnstufe. Bei totem Code, der durch den Kontrollfluss des Programms verursacht wird, erkennt JDK dies als Fehler.

Unten ist mein Versuch:

    public class Setting {
        public static final boolean FianlDebugFlag = false;
    }


    class B {
    .....

    // no warn, it is typical "IF" conditional compilataion code
    if(Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   
    if(false) 
        System.out.println("am i dead?");   


    // warn, as the dead code is caused by a constant boolean flag
    if(ret!=null && Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   

    if(Setting.FinalDebug)                  
        return null;                                                            
    System.out.println("am i dea?");        

    // error, as the dead code is due to the program's control flow
    return null;
    System.out.println("am i dead");        
    }

.

224370cookie-checkUnerreichbarer Codefehler vs. Tote Code-Warnung in Java unter Eclipse?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy