2014-06-12 5 views
5

Wenn eine Anweisung nach der Endlosschleife geschrieben wird, wird diese Anweisung zum unerreichbaren Code. Zum Beispiel:Wann tritt in Java die Bedingung "Unreachable Code" auf?

for(;;) 
{ 
} 
Sytem.out.println("Test-1"); //unreachable code 

Aber ich stehe hier einige Schwierigkeiten.

Blick auf die beiden Code-Snippets unter:

-Code snippet1:

for(final int z=4;z<6;) 
{ 
} 
System.out.println("Test-2"); //unreachable code 

Hier Die letzte Aussage muss nicht erreichbar sein, weil die Schleife unendlich ist und der Ausgang wird wie erwartet.

-Code Snippet2:

final int z=4; 
for(;;) 
{ 
    if(z<2) 
     break; 
} 
System.out.println("Test-3"); //not unreachable 

Konzeptionell ist die for-Schleife in obigem Code auch unendlich, da z endgültig und if(z<2) bei der Kompilierung only.The bestimmt wird, wenn die Bedingung wird nie wahr sein und die Schleife wird nie Unterbrechung. Aber die Last-Anweisung im obigen Code ist nicht unerreichbar.

Fragen:

  1. Warum dies geschieht?

  2. Kann jemand mir die genauen Regeln sagen, durch die wir sehen können, ob Code unerreichbar ist oder nicht.

+7

Java-Sprachspezifikation hat die Antwort: [Nicht erreichbare Anweisungen] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21) – Christian

+2

@ Gynnad, Sie breche nur wenn z <2, was nicht ist. (Die Frage könnte sich geändert haben) – Holloway

Antwort

3

Der Schlüsselsatz in http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21 ist:

Es ist ein Fehler bei der Kompilierung, wenn eine Anweisung nicht, weil ausgeführt werden kann es nicht erreichbar ist.

Dieser Abschnitt ist einer genauen Erläuterung des Worts "erreichbar" gewidmet. Die Idee ist, dass es eine mögliche Ausführung Pfad vom Anfang des Konstruktors, Methode, Instanz Initialisierer oder statischen Initialisierer geben muss, die die Anweisung an die Anweisung selbst enthält. Die Analyse berücksichtigt die Struktur von Aussagen. Mit Ausnahme der speziellen Behandlung von while, do und für Anweisungen, deren Bedingungsausdruck den konstanten Wert true hat, werden die Werte von Ausdrücken in der Ablaufanalyse nicht berücksichtigt.

Daher der Compiler wertet nicht z<2 in Ihrer if() Aussage, und weiß nicht, , dass es nie zu true bewerten.

Dies definiert nicht erreichbaren Code, soweit die Java-Spezifikation betroffen ist. Es ist wichtig, dass Compiler sich an die Spezifikation halten, da das Ändern der Regeln dazu führen kann, dass Code, der kompiliert wurde, nicht kompiliert werden kann.

Compiler können jedoch Warnungen statt Kompilierungsfehler geben.

Wenn ich den folgenden Code in Eclipse Typ:

final int x = 0; 
if(x == 1) { 
    System.out.println("This never happens"); 
} 

... Ich erhalte die Warnung "Dead Code". Der Compiler weiß, dass der Code nicht erreichbar ist - aber er kann die Kompilierung nicht ablehnen, da der Code laut Java-Spezifikation nicht formal "unerreichbar" ist.

+0

Ja, es hat geholfen. Aber nachdem ich dies gelesen hatte, tauchte ein weiterer Zweifel in meinem Kopf auf. Nehmen wir ein Beispiel: code1: 'int a = 4, b; if (a == 4) b = 5; System.out.println (b); // error-b wurde möglicherweise nicht initialisiert ' Dies ist vollkommen richtig, da die Initialisierung von b innerhalb von if ist. Aber in dem folgenden Code: final int a = 4, b; if (a == 4) b = 5; System.out.println (b); // gibt keinen Fehler ' Aufgrund Ihrer obigen Argumentation sollte dies auch einen Fehler anzeigen, da der Wert des Ausdrucks in der if-Bedingung nicht ausgewertet werden sollte. –

+0

In diesem Fall ist der Fehler nicht "Nicht erreichbarer Code", daher gelten die Spezifikationen in diesem Abschnitt nicht. Was Sie dort haben, ist ein konstanter Ausdruck, der bei der Kompilierung zu "if (true)" auswertet. Der Compiler wird das 'if()' out komplett streichen und nur inline 'b = 5'. Es ist ein "konstanter Ausdruck", weil "a" "final" ist. – slim

+0

http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28 – slim

0
for(final int z=4;z<6;) 
{ 
} 
System.out.println("Test-2"); //unreachable code --> z is final. Its value can't change. There is no way out of that loop 



final int z=4; 
for(;;) 
{ 
    if(z<2) // z is 4 . The compiler only knows the value of "z". It doesn't know what z<2 evaluates to.. So, it still thinks taht there is a chance of getting out of that loop. 
break; 
} 
System.out.println("Test-3"); //So --> reachable code. 
+0

Bitte schauen Sie sich den Code-Snippet-2 noch einmal an. Es ist z <2 dort. –

+0

@VikasMangal - check my edit .. – TheLostMind

2

Von http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21

14,21. Nicht erreichbare Anweisungen

Es ist ein Kompilierungsfehler, wenn eine Anweisung nicht ausgeführt werden kann, weil nicht erreichbar ist.

Dieser Abschnitt ist einer genauen Erläuterung des Worts "erreichbar" gewidmet. Die Idee ist, dass es eine mögliche Ausführung Pfad vom Anfang des Konstruktors, Methode, Instanz Initialisierer oder statischen Initialisierer geben muss, die die Anweisung an die Anweisung selbst enthält. Die Analyse berücksichtigt die Struktur von Aussagen. Mit Ausnahme der speziellen Behandlung von while, do und für Anweisungen, deren Bedingungsausdruck den konstanten Wert true hat, werden die Werte von Ausdrücken in der Ablaufanalyse nicht berücksichtigt.

Zum Beispiel wird ein Java-Compiler den Code akzeptieren:

{ int n = 5; während (n> 7) k = 2; } obwohl der Wert von n zur Kompilierzeit bekannt ist und im Prinzip zur Kompilierzeit bekannt sein kann, dass die Zuweisung zu k nie ausgeführt werden kann.

Die Regeln in diesem Abschnitt definieren zwei Fachbegriffe:

, ob eine Aussage

erreichbar ist, ob eine Aussage normalerweise

Die Definitionen hier abschließen erlauben eine Aussage nur zu vervollständigen normalerweise, wenn es ist erreichbar.

Um die Beschreibung der Regeln zu verkürzen, wird die übliche Abkürzung "iff" verwendet "wenn und nur wenn".

Eine erreichbare break-Anweisung beendet eine Aussage, wenn innerhalb der Pause Ziels, entweder gibt es keine try-Anweisungen, die versuchen Blöcke enthalten die break-Anweisung, oder gibt es Aussagen versuchen, deren versuchen Blöcke die break-Anweisung enthalten und alle schließlich Klauseln dieser Versuche Anweisungen können normal abgeschlossen werden.

Diese Definition basiert auf der Logik um "Versuche, Kontrolle zu übertragen" in §14.15.

Eine Aussage weiterhin weiterhin eine do-Anweisung, wenn innerhalb der Anweisung tun, entweder gibt es keine try-Anweisungen, deren Blöcke versuchen enthalten die Aussage weiter, oder es werden Aussagen versuchen, deren versuchen Blöcke enthalten die Aussage fortsetzen und alle endlich Klauseln dieser Versuche Anweisungen können normal abgeschlossen werden.

Die Regeln sind wie folgt:

der Block, der Körper eines Konstruktors ist, ein Verfahren, beispielsweise Initialisierer oder statische Initialisierer erreichbar ist.

Ein leerer Block, der kein Schaltblock ist, kann normal abgeschlossen werden, wenn erreichbar ist.

Ein nicht leerer Block, der kein Schaltblock ist, kann normal beendet werden, wenn die letzte Anweisung darin normal abgeschlossen werden kann. Die erste Anweisung in einem nicht leeren Block, der kein Schaltblock ist, ist erreichbar, wenn der Block erreichbar ist.

Jede andere Anweisung S in einem nicht leeren Block, der kein Schalter ist Block ist erreichbar, wenn die Anweisung vor S normal abgeschlossen werden kann.

Eine lokale Klassendeklarationsanweisung kann normal abgeschlossen werden, wenn sie erreichbar ist.

Eine lokale Variablendeklarationsanweisung kann normal abgeschlossen werden, wenn sie erreichbar ist.

Eine leere Anweisung kann normalerweise abgeschlossen werden, wenn sie erreichbar ist.

Markiertes Anweisung kann normalerweise ausgeführt werden, wenn mindestens eine der folgenden zutrifft:

Die enthaltene Anweisung kann normalerweise vervollständigen.

Es gibt eine erreichbare break-Anweisung, die die beschriftete Anweisung beendet.

Die enthaltene Anweisung ist erreichbar, wenn die beschriftete Anweisung erreichbar ist.

Eine Ausdruckanweisung kann normalerweise abgeschlossen werden, wenn sie erreichbar ist.

Eine Wenn-Dann-Anweisung kann normal abgeschlossen werden, wenn sie erreichbar ist.

Die then-Anweisung ist erreichbar, wenn die if-then-Anweisung erreichbar ist.

Eine if-then-else-Anweisung kann normal abgeschlossen werden, wenn die then-Anweisung normal beendet werden kann oder die else-Anweisung normal abgeschlossen werden kann.

Die then-Anweisung ist erreichbar, wenn die if-then-else-Anweisung erreichbar ist.

Die else-Anweisung ist erreichbar, wenn die if-then-else-Anweisung erreichbar ist.

Diese Behandlung einer if-Anweisung, ob sie einen anderen Teil hat oder nicht, ist eher ungewöhnlich. Die Begründung wird am Ende dieses Abschnitts gegeben.

Eine assert-Anweisung kann normal abgeschlossen werden, wenn sie erreichbar ist.

eine switch-Anweisung kann normal abzuschließen iff mindestens einer der folgenden Bedingungen zutrifft:

Der Schaltblock ist leer oder enthält nur Etiketten wechseln.

Die letzte Anweisung im Schaltblock kann normal abgeschlossen werden.

Es gibt mindestens eine Schalterbezeichnung nach dem letzten Schalterblock Anweisungsgruppe.

Der Switch-Block enthält keine Standardbezeichnung.

Es gibt eine erreichbare break-Anweisung, die die switch-Anweisung beendet.

Ein Schalterblock ist erreichbar, wenn seine Schalteranweisung erreichbar ist.

A-Anweisung in einem Schalterblock erreichbar ist genau dann, wenn seine Schalt Anweisung erreichbar und mindestens eine der folgenden Bedingungen erfüllt ist:

es einen Fall oder Standard-Label trägt.

Es gibt eine Anweisung davor im Schaltblock und vorhergehende Anweisung kann normal abgeschlossen werden.

A während Anweisung kann normalerweise mindestens Iff Führen Sie eine der folgenden Aussagen zutreffen :

Die while-Anweisung ist erreichbar und der Bedingungsausdruck ist kein konstanter Ausdruck (§15.28) mit dem Wert wahr.

Es gibt eine erreichbare break-Anweisung, die die while-Anweisung beendet.

Die enthaltene Anweisung ist erreichbar, wenn die while-Anweisung erreichbar ist und der Bedingungsausdruck kein konstanter Ausdruck ist, dessen Wert false ist.

A do Anweisung kann normalerweise iff mindestens eine der folgenden Vorgang auszuführen wahr ist:

Die enthaltene Anweisung kann normalerweise vervollständigen und die Bedingung Ausdruck keinen Konstante Ausdruck (§15.28) mit dem Wert wahr.

Die do-Anweisung enthält eine erreichbare Anweisung ohne Label weiter, und die Aussage zu tun ist die innerste, während, tun oder für Anweisung, die enthält, die Aussage weiter, und die weiterhin Aussage weiterhin diese Aussage tun, und die Bedingung Ausdruck ist kein konstanter Ausdruck mit Wert True.

Die do-Anweisung enthält eine erreichbare Anweisung mit einem Etikett L weiter, und das tun Anweisung hat Etikett L, und die Anweisung continue diese Aussage nicht weiter, und die Bedingung Ausdruck keine konstanter Ausdruck mit dem Wert wahr.

Es gibt eine erreichbare break-Anweisung, die die do-Anweisung beendet.

Die enthaltene Anweisung ist erreichbar, genau dann, wenn die do-Anweisung ist erreichbar.

Eine grundlegende für Anweisung kann normalerweise vervollständigen iff mindestens einer der folgenden Punkte zutrifft:

Die for-Anweisung erreichbar ist, gibt es eine Bedingung, Ausdruck und die Bedingung Ausdruck ist nicht ein konstanter Ausdruck (§ 15.28) mit Wert wahr.

Es gibt eine erreichbare break-Anweisung, die die for-Anweisung beendet.

Die enthaltene Anweisung ist erreichbar, wenn die for-Anweisung erreichbar ist und der Bedingungsausdruck kein konstanter Ausdruck ist, dessen Wert false ist.

Eine erweiterte for-Anweisung kann normalerweise abgeschlossen werden, wenn sie erreichbar ist.

Ein Bruch, continue, return oder throw-Anweisung kann normalerweise nicht abgeschlossen.

Eine synchronisierte Anweisung kann normalerweise vervollständigen iff die enthaltene Anweisung normal abschließen.

Die enthaltene Anweisung ist erreichbar iff die synchronisierte Anweisung ist erreichbar.

Eine try-Anweisung ausführen können normalerweise iff die beiden folgenden sind wahr:

Der try-Block vervollständigen normalerweise kann oder jeder Block fangen kann normalerweise abzuschließen.

Wenn die try-Anweisung einen finally-Block hat, dann kann der finally-Block normal vervollständigen.

Der try-Block ist erreichbar, wenn die try-Anweisung erreichbar ist.

A Fangblock C erreichbar ist iff beide der folgenden Bedingungen erfüllt sind:

Entweder ist die Art des C des Parameters ist ein ungeprüfter Ausnahmetyp oder Throwable; oder einige Ausdruck oder throw-Anweisung im try-Block ist erreichbar und kann eine geprüfte Ausnahme, deren Typ zuweisbare dem Parameter der catch-Klausel C.

Ein Ausdruck ist erreichbar iff die innerste Aussage werfen enthält es erreichbar ist .

Siehe §15.6 für normale und abrupte Vervollständigung von Ausdrücken.

Es gibt keinen früheren catch-Block A in der try-Anweisung, so dass der Typ des C-Parameters der gleiche oder eine Unterklasse des Typs von A ist.

Der Block eines Catch-Blocks ist erreichbar, wenn der Catch-Block erreichbar ist. Wenn ein finally-Block vorhanden ist, ist er erreichbar, wenn die try-Anweisung erreichbar ist.

Verwandte Themen