2015-09-10 7 views
21

den folgenden Java-Code-Schnipsel Nehmen:(Compiler) else if (true) vs anderes Szenario

.... 
    else if (true){ //hard-coded as true 
    ///launch methodA 
    } 
    else { 
    ///launch methodA (same code as in the ` else if ` statement) 
    } 
.... 

Was ich frage mich, wie die Compiler beschäftigt sich mit dieser. Wäre es nicht logisch für den Compiler, die else if(true)-Anweisung vollständig zu entfernen, um keine Prüfung durchführen zu müssen, obwohl sie fest als wahr codiert ist. Wie wird der obige Code speziell in Eclipse interpretiert?

Oder was ist in dem folgende Szenario:

.... 
    else if (true){ //hard-coded as true 
    ///launch methodA 
    } 
    else { 
    ///launch methodBB 
    } 
.... 

Wäre es in diesem Fall nicht logisch sein, dass der Compiler die else Anweisung zu entfernen? Denn während der Ausführung ist die else-Anweisung nicht erreichbar.

+0

Nur wundernd ... der logischste (oder zumindest der effizienteste) wäre der Compiler, nur die 'launch methodA' zu lassen, in beiden Fällen. – brlaranjeira

+0

"Wäre es nicht logisch ..." Ja, und das tun die meisten modernen Compiler. –

Antwort

19

Nicht erreichbare Anweisungen sind in Java verboten und müssen Kompilierungsfehler auslösen. Die JLS definiert, was ist ein unerreichbares Aussagen: https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21

Es ist zu lang ganz hier zitiert zu werden, aber hier ist ein Extrakt (Schwerpunkt von mir):

if (false) { x=3; } 

nicht in Folge hat ein Fehler bei der Kompilierung Ein optimierender Compiler kann erkennen, dass die Anweisung x = 3; wird nie ausgeführt und kann wählen, um den Code für diese Anweisung aus der generierten Klassendatei wegzulassen, aber die Anweisung x = 3; wird nicht als "unerreichbar" in dem technischen Sinn angesehen, der hier spezifiziert ist.

Der Grund für diese unterschiedliche Behandlung ist Programmierer zu ermöglichen „Flag-Variablen“ definieren, wie:

static final boolean DEBUG = false; 

und dann Code schreiben wie:

if (DEBUG) { x=3; } 

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

Die Antwort hängt also vom verwendeten Compiler und seinen Optimierungsoptionen ab.

+2

Darüber hinaus wäre es ziemlich ärgerlich, wenn ein Programmierer, der eine Variable wie 'static boolean enableLogging;' besitzt, die eigentlich * als Variable * benutzt wird, diese später nicht in 'static final boolean elableLogging = false; um den gesamten Code, der es liest, manuell zu bearbeiten. – supercat

2

Über Eclipse insbesondere wird es Sie warnen, dass der letzte else Block nicht erreichbar ist, aber die Kompilierung an Ihren jdk delegiert wird, vielleicht ist es der Compiler, der Eclipse warnt.

+3

Eigentlich hat Eclipse seinen eigenen Compiler 'ecj' (Eclipse Compiler für Java). Suns/Oracles 'javac' (geschrieben von Martin Odersky, dem Designer von Scala) ist ein Batch-Compiler, der nicht für den interaktiven, inkrementellen Gebrauch gedacht ist. 'ecj' ist (wie alle anderen von Eclipse) von IBM VisualAge für Smalltalk abgeleitet und somit speziell für die interaktive, inkrementelle Kompilierung" while-you-type "in einer IDE konzipiert. –

3

Es gibt keine bestimmte Antwort auf diese Frage. Es hängt vom Java Compiler ab. Die meisten Compiler ignorieren den Dead Code, da er die Semantik des Codes nicht ändert, selbst wenn dies zu einer größeren Klassendatei führt.

Wenn Sie an einer solchen Analyse interessiert sind, gibt es eine Menge Literatur über die Beseitigung von Dead Code.

3

Sie können versuchen, den Code zu schreiben und die Klassendatei zu dekompilieren. Mein Compiler optimiert

else if (true){ //hard-coded as true 
///launch methodA 
} 
else { 
///launch methodA (same code as in the else if statement) 
} 

als

else { 
///launch methodA 
} 

und

else if (true){ //hard-coded as true 
///launch methodA 
} 
else { 
///launch methodBB 
} 

als

else { 
///launch methodA 
} 

Ich denke, alle Compiler-Versionen auf diese Weise optimieren.

10

Der Compiler optmizes es bei der Kompilierung:

public class Test { 
    public static void main(String[] args) { 
    if(true) { 
     System.out.println("Hello"); 
    } else { 
     System.out.println("Boom"); 
    } 
} 

mich gibt (mit meinem Java 1.8.0_45):

Compiled from "Test.java" 
public class Test { 
    publicTest(); 
    Code: 
     0: aload_0 
     1: invokespecial #1  // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: getstatic  #2  // Field java/lang/System.out:Ljava/io/PrintStream; 
     3: ldc   #3  // String Hello 
     5: invokevirtual #4  // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     8: return 
} 

Der Code nur Hello druckt. Boom wird nicht einmal berücksichtigt.

Alle neueren Java-Compiler eliminieren toten Code zur Kompilierzeit.

2

jetzt i-Code schreiben meine Methode in Eclipse

 public static void aa(String b){ 
     if (true) { 

     } 

     else if (true) { 
      System.out.println("asas"); 
     } else { 

     } 
     } 

Nachdem ich meinen Code kompiliert und ich meinen Code Decompiler mit JD-GUI.My Decompiler-Code ist:

public static void aa(String b) {} 

}

Ergebnis ist sehr gut :)

1

Wouldn Es ist logisch für den Compiler, die else if (true) -Anweisung vollständig zu entfernen, um keine Überprüfung durchführen zu müssen, obwohl sie hart als wahr codiert ist.

Nein, würde es nicht, es sei denn, beide Blöcke hatten den gleichen Inhalt, und warum sollte es dafür prüfen? Es wäre semantisch inkorrekt. Was wäre logisch wäre für den Compiler zu entfernen die endgültige unerreichbar else, und das ist, was es tut.