Die Besonderheiten des Java-Falls (die wahrscheinlich dem C # -Fall sehr ähnlich sind) hängen damit zusammen, wie der Java-Compiler bestimmt, ob eine Methode zurückkehren kann.
Insbesondere gilt die Regel, dass eine Methode mit einem Rückgabetyp nicht normal abgeschlossen werden darf und stattdessen immer abgeschlossen werden muss abrupt (hier abrupt über eine return-Anweisung oder eine Ausnahme) gemäß JLS 8.4.7 abgeschlossen werden muss .
Wenn für eine Methode ein Rückgabetyp deklariert wird, tritt ein Fehler zur Kompilierungszeit auf, wenn der Hauptteil der Methode normal abgeschlossen werden kann. Mit anderen Worten, eine Methode mit einem Rückgabetyp darf nur mithilfe einer return-Anweisung zurückgegeben werden, die eine Wertrückgabe bereitstellt. es ist nicht erlaubt, "das Ende seines Körpers fallen zu lassen" .
Der Compiler prüft, ob eine normale Beendigung vorliegt anhand der in JLS 14.21 Unreachable Statements definierten Regeln, möglich ist, da er auch die Regeln für die normale Fertigstellung definiert.
Insbesondere die Regeln für nicht erreichbare Anweisungen machen einen Sonderfall nur für Schleifen, die eine definierte haben true
konstanten Ausdruck haben:
Eine while-Anweisung kann normal ausgeführt werden, wenn mindestens eine der folgenden Aussagen zutrifft:
Die while-Anweisung ist erreichbar und der Bedingungsausdruck ist kein konstanter Ausdruck (§15.28) mit dem Wert true.
Es gibt eine erreichbare break-Anweisung, die die while-Anweisung beendet.
Wenn die while
Anweisung normal ausgeführt werden kann , ist eine folgende return-Anweisung erforderlich, da der Code als erreichbar angesehen wird und jede while
Schleife ohne erreichbare break-Anweisung oder Konstantetrue
Ausdruck als normal ausgeführt werden kann.
Diese Regeln bedeuten , dass Ihre while
Aussage mit einem konstanten wahren Ausdruck und ohne break
wird normalerweise nie abgeschlossen betrachtet , und so jeder Code unten ist nie erreichbar sein betrachtet . Das Ende der Methode befindet sich unterhalb der Schleife, und da alles unterhalb der Schleife nicht erreichbar ist, ist dies auch das Ende der Methode, und daher kann die Methode möglicherweise nicht normal abgeschlossen werden (wonach der Complier sucht).
if
Anweisungen hingegen haben keine besondere Ausnahme für konstante Ausdrücke, die Schleifen gewährt werden.
Vergleichen Sie:
// I have a compiler error!
public boolean testReturn()
{
final boolean condition = true;
if (condition) return true;
}
Mit:
// I compile just fine!
public boolean testReturn()
{
final boolean condition = true;
while (condition)
{
return true;
}
}
Der Grund für die Unterscheidung ist sehr interessant und beruht auf dem Wunsch, bedingte Kompilierungsflags zuzulassen, die keine Compilerfehler verursachen (vom JLS):
Man könnte erwarten, dass die if-Anweisung folgendermaßen behandelt wird:
Eine Wenn-Dann-Anweisung kann normal ausgeführt werden, wenn mindestens eine der folgenden Aussagen zutrifft:
Die if-then-Anweisung ist erreichbar und der Bedingungsausdruck ist kein konstanter Ausdruck, dessen Wert wahr ist.
Die then-Anweisung kann normal abgeschlossen werden.
Die then-Anweisung ist erreichbar, wenn die if-then-Anweisung erreichbar ist und der Bedingungsausdruck kein konstanter Ausdruck ist, dessen Wert falsch ist.
Eine if-then-else-Anweisung kann normal ausgeführt werden, wenn die then-Anweisung normal oder die else-Anweisung normal ausgeführt werden kann.
Die then-Anweisung ist erreichbar, wenn die if-then-else-Anweisung erreichbar ist und der Bedingungsausdruck kein konstanter Ausdruck ist, dessen Wert falsch ist.
Die else-Anweisung ist erreichbar, wenn die if-then-else-Anweisung erreichbar ist und der Bedingungsausdruck kein konstanter Ausdruck ist, dessen Wert wahr ist.
Dieser Ansatz wäre mit der Behandlung anderer Kontrollstrukturen vereinbar. Damit die if-Anweisung jedoch bequem für Zwecke der "bedingten Kompilierung" verwendet werden kann, unterscheiden sich die tatsächlichen Regeln.
Die folgende Anweisung führt beispielsweise zu einem Fehler bei der Kompilierung:
while (false) { x=3; }
weil die Aussage x=3;
nicht erreichbar ist; aber der oberflächlich ähnliche Fall:
if (false) { x=3; }
führt nicht zu einem Fehler bei der Kompilierung. Ein optimierender Compiler kann erkennen, dass die Anweisung x=3;
niemals ausgeführt wird, und kann den Code für diese Anweisung aus der generierten Klassendatei weglassen, aber die Anweisung x=3;
wird im hier angegebenen technischen Sinne nicht als "nicht erreichbar" angesehen.
Der Grund für diese unterschiedliche Behandlung besteht darin, Programmierern die Definition von "Flag-Variablen" zu ermöglichen, wie z.
static final boolean DEBUG = false;
und schreiben Sie dann Code wie:
if (DEBUG) { x=3; }
Die Idee ist, dass es möglich sein sollte, den Wert von DEBUG von false in true oder von true in false zu ändern und dann den Code ohne weitere Änderungen am Programmtext korrekt zu kompilieren.
Warum führt die bedingte break-Anweisung zu einem Compilerfehler?
Wie in den Regeln für die Erreichbarkeit von Schleifen angegeben, kann eine while-Schleife auch normal abgeschlossen werden, wenn sie eine erreichbare break-Anweisung enthält. Da die Regeln für die Erreichbarkeit der then- Klausel einer if
Anweisung die Bedingung der Anweisung überhaupt nicht berücksichtigen, gilt eine solche bedingte Anweisung dannif
if
Klausel immer als erreichbar angesehen.
Ist das break
erreichbar, so gilt der Code nach der Schleife wieder als erreichbar. Da es keinen erreichbaren Code gibt, der zu einer abrupten Beendigung nach der Schleife führt, wird die Methode als normal abgeschlossen angesehen, und der Compiler kennzeichnet sie als Fehler.