Frage 1:
Warum wird der folgende Code ohne return-Anweisung kompiliert?
public int a()
{
while(true);
}
Dies wird durch JLS§8.4.7 abgedeckt :
Wenn für eine Methode ein Rückgabetyp deklariert wird (§8.4.5), tritt ein Fehler bei der Kompilierung auf, wenn der Hauptteil der Methode normal abgeschlossen werden kann (§14.1).
Mit anderen Worten, eine Methode mit einem Rückgabetyp darf nur mithilfe einer return-Anweisung zurückgegeben werden, die eine Wertrückgabe bereitstellt. Die Methode darf nicht "das Ende ihres Körpers fallen lassen". In §14.17 finden Sie die genauen Regeln für return-Anweisungen in einem Methodenkörper.
Es ist möglich, dass eine Methode einen Rückgabetyp hat und dennoch keine Rückgabeanweisungen enthält. Hier ist ein Beispiel:
class DizzyDean {
int pitch() { throw new RuntimeException("90 mph?!"); }
}
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 gibt return
.
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);
}
In diesem 0 == 0
Fall weiß der Compiler, dass die Schleife niemals beendet wird (das 0 == 0
wird immer wahr sein). Aber das weiß es nicht für b == 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) :
Einige Ausdrücke haben einen Wert, der zur Kompilierungszeit festgelegt werden kann. Dies sind konstante Ausdrücke (§15.28).
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, wenn b
ein double
, wie QBrute betonte , leicht getäuscht werden könnte Double.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 mit a + 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 eines return
.