Frage 1:
Warum wird der folgende Code ohne return-Anweisung kompiliert?
public int a() {
while(true);
}
Hinweis: Wenn ich nach einiger Zeit eine Rückgabe hinzufüge, erhalte ich eine Unreachable Code Error
.
Frage 2:
Warum wird der folgende Code kompiliert?
public int a() {
while(0 == 0);
}
obwohl das folgende nicht.
public int a(int b) {
while(b == b);
}
java
syntax
while-loop
compilation
return
Willi Mentzel
quelle
quelle
Antworten:
Dies wird durch JLS§8.4.7 abgedeckt :
Da der Compiler weiß, dass die Schleife niemals beendet wird (
true
ist natürlich immer wahr), weiß er, dass die Funktion nicht "normal zurückkehren" kann (das Ende ihres Körpers fallen lassen), und daher ist es in Ordnung, dass es keine gibtreturn
.In diesem
0 == 0
Fall weiß der Compiler, dass die Schleife niemals beendet wird (das0 == 0
wird immer wahr sein). Aber das weiß es nicht fürb == b
.Warum nicht?
Der Compiler versteht konstante Ausdrücke (§15.28) . Zitieren von §15.2 - Formen von Ausdrücken (weil dieser Satz seltsamerweise nicht in §15.28 enthalten ist) :
b == b
Da es sich in Ihrem Beispiel um eine Variable handelt, handelt es sich nicht um einen konstanten Ausdruck und es wird nicht angegeben, dass er zur Kompilierungszeit bestimmt werden soll. Wir können sehen, dass es in diesem Fall immer wahr sein wird (obwohl, wennb
eindouble
, wie QBrute betonte , leicht getäuscht werden könnteDouble.NaN
, was nicht==
selbst ist ), aber das JLS spezifiziert nur, dass konstante Ausdrücke zur Kompilierungszeit bestimmt werden Der Compiler kann nicht versuchen, nicht konstante Ausdrücke auszuwerten. bayou.io hat einen guten Punkt angesprochen , warum nicht: Wenn Sie versuchen, Ausdrücke mit Variablen zur Kompilierungszeit zu bestimmen, wo hören Sie dann auf?b == b
ist offensichtlich (ähm, für Nicht-NaN
Werte), aber was ist mita + b == b + a
? Oder(a + b) * 2 == a * 2 + b * 2
? Das Zeichnen der Linie bei Konstanten ist sinnvoll.Da der Ausdruck nicht "bestimmt" wird, weiß der Compiler nicht, dass die Schleife niemals beendet wird, und glaubt daher, dass die Methode normal zurückkehren kann - was nicht zulässig ist, da sie verwendet werden muss
return
. Es beschwert sich also über das Fehlen einesreturn
.quelle
Es kann interessant sein, sich einen Methodenrückgabetyp nicht als Versprechen vorzustellen, einen Wert des angegebenen Typs zurückzugeben, sondern als Versprechen, keinen Wert zurückzugeben, der nicht vom angegebenen Typ ist. Wenn Sie also niemals etwas zurückgeben, brechen Sie das Versprechen nicht, und daher ist Folgendes legal:
Für immer schleifen:
Für immer wiederkehren:
Eine Ausnahme ausschließen:
(Ich finde, dass die Rekursion Spaß macht: Der Compiler glaubt, dass die Methode einen Wert vom Typ
X
(was auch immer das ist) zurückgibt, aber es ist nicht wahr, da kein Code vorhanden ist, der eine Idee zum Erstellen oder hat beschaffen anX
.)quelle
Wenn der zurückgegebene Bytecode nicht mit der Definition übereinstimmt, wird ein Kompilierungsfehler angezeigt.
Beispiel:
for(;;)
zeigt die Bytecodes:Beachten Sie das Fehlen eines Rückgabebytecodes
Dies führt nie zu einer Rückgabe und gibt daher nicht den falschen Typ zurück.
Zum Vergleich eine Methode wie:
Gibt die folgenden Bytecodes zurück:
Beachten Sie die "Rückkehr", was "Rückgabe einer Referenz" bedeutet.
Wenn wir nun Folgendes tun:
Gibt die folgenden Bytecodes zurück:
Jetzt können wir sehen, dass der Typ in der Definition nicht mit dem Rückgabetyp von ireturn übereinstimmt, was return int bedeutet.
Es kommt also wirklich darauf an, dass, wenn die Methode einen Rückgabepfad hat, dieser Pfad mit dem Rückgabetyp übereinstimmen muss. Es gibt jedoch Fälle im Bytecode, in denen überhaupt kein Rückgabeweg generiert wird und somit kein Verstoß gegen die Regel vorliegt.
quelle