Ich bin auf eine Situation gestoßen, in der einer nicht ungültigen Methode eine return- Anweisung fehlt und der Code immer noch kompiliert wird. Ich weiß, dass die Anweisungen nach der while-Schleife nicht erreichbar sind (toter Code) und niemals ausgeführt werden würden. Aber warum warnt der Compiler nicht einmal davor, etwas zurückzugeben? Oder warum sollte eine Sprache es uns ermöglichen, eine nicht leere Methode mit einer Endlosschleife zu haben und nichts zurückzugeben?
public int doNotReturnAnything() {
while(true) {
//do something
}
//no return statement
}
Wenn ich der while-Schleife eine break-Anweisung (auch eine bedingte) hinzufüge, beschwert sich der Compiler über die berüchtigten Fehler: Method does not return a value
in Eclipse und Not all code paths return a value
in Visual Studio.
public int doNotReturnAnything() {
while(true) {
if(mustReturn) break;
//do something
}
//no return statement
}
Dies gilt sowohl für Java als auch für C #.
unreachable statement
ob es nach der Schleife etwas gibt .Antworten:
Die Regel für nicht ungültige Methoden lautet, dass jeder zurückgegebene Codepfad einen Wert zurückgeben muss. Diese Regel ist in Ihrem Programm erfüllt: Null von null Codepfaden, die zurückgeben, geben einen Wert zurück. Die Regel lautet nicht "Jede nicht ungültige Methode muss einen Codepfad haben, der zurückgibt".
Auf diese Weise können Sie Stub-Methoden schreiben wie:
Das ist eine nicht leere Methode. Es muss eine nicht leere Methode sein, um die Schnittstelle zu erfüllen. Es erscheint jedoch albern, diese Implementierung illegal zu machen, da sie nichts zurückgibt.
Dass Ihre Methode einen nicht erreichbaren Endpunkt hat, weil a
goto
(denken Sie daran, awhile(true)
ist nur eine angenehmere Art zu schreibengoto
) anstelle von athrow
(was eine andere Form von istgoto
), ist nicht relevant.Weil der Compiler keine guten Beweise dafür hat, dass der Code falsch ist. Jemand hat geschrieben
while(true)
und es scheint wahrscheinlich, dass die Person, die das getan hat, wusste, was sie tat.Siehe meine Artikel zu diesem Thema hier:
ATBG: de facto und de jure Erreichbarkeit
Sie können auch die C # -Spezifikation lesen.
quelle
public int doNotReturnAnything() {
boolean flag = true;
while (flag) {
//Do something
}
//no return
}
Dieser Code hat auch keinen Haltepunkt. Wie der Compiler nun weiß, ist der Code falsch.if
,while
,for
,switch
, usw., Verzweigungs Konstrukte , die auf betreiben Konstanten als unbedingte Verzweigungen durch den Compiler behandelt werden. Die genaue Definition des konstanten Ausdrucks finden Sie in der Spezifikation. Die Antworten auf Ihre Fragen finden Sie in der Spezifikation. Mein Rat ist, dass Sie es lesen.Every code path that returns must return a value
Beste Antwort. Behebt beide Fragen eindeutig. DankeDer Java-Compiler ist intelligent genug, um den nicht erreichbaren Code (den Code nach der
while
Schleife) zu finden.und da es nicht erreichbar ist , macht es keinen Sinn , dort eine
return
Aussage hinzuzufügen (nach demwhile
Ende)Gleiches gilt für bedingte
if
Da die boolesche Bedingung
someBoolean
nur entwedertrue
oder auswerten kannfalse
, muss keinreturn
explizites Nachher angegeben werdenif-else
, da dieser Code nicht erreichbar ist und Java sich nicht darüber beschwert.quelle
return
Anweisung in nicht erreichbarem Code benötigen , hat aber nichts damit zu tun, warum Sie keinereturn
Anweisung im OP-Code benötigen .public int doNotReturnAnything() {
if(true){
System.exit(1);
}
return 11;
}
public int doNotReturnAnything() {
while(true){
System.exit(1);
}
return 11;// Compiler error: unreachable code
}
System.exit(1)
das Programm dadurch beendet wird. Es können nur bestimmte Arten von nicht erreichbarem Code erkannt werden.System.exit(1)
dass er das Programm beenden wird. Wir können jedes verwendenreturn statement
, jetzt erkennt der Compiler dasreturn statements
. Und das Verhalten ist das gleiche, Rückgabe erfordert für,if condition
aber nicht fürwhile
.while(true)
Der Compiler weiß, dass die
while
Ausführung der Schleife niemals beendet wird, daher wird die Methode niemals beendet, daher ist einereturn
Anweisung nicht erforderlich.quelle
Vorausgesetzt, Ihre Schleife wird auf einer Konstanten ausgeführt - der Compiler weiß, dass es sich um eine Endlosschleife handelt -, bedeutet dies, dass die Methode sowieso niemals zurückkehren könnte.
Wenn Sie eine Variable verwenden, erzwingt der Compiler die Regel:
Dies wird nicht kompiliert:
quelle
Die Java-Spezifikation definiert ein Konzept namens
Unreachable statements
. Sie dürfen keine nicht erreichbare Anweisung in Ihrem Code haben (dies ist ein Fehler bei der Kompilierung). Nach der Weile dürfen Sie nicht einmal mehr eine return-Anweisung haben (true). Anweisung in Java. Einewhile(true);
Anweisung macht die folgenden Anweisungen per Definition nicht erreichbar, daher benötigen Sie keinereturn
Anweisung.Beachten Sie, dass das Problem des Anhaltens im allgemeinen Fall zwar nicht zu entscheiden ist, die Definition der nicht erreichbaren Anweisung jedoch strenger ist als nur das Anhalten. Es entscheidet über ganz bestimmte Fälle, in denen ein Programm definitiv nicht anhält. Der Compiler ist theoretisch nicht in der Lage, alle Endlosschleifen und nicht erreichbaren Anweisungen zu erkennen, muss jedoch bestimmte in der Spezifikation definierte Fälle erkennen (z. B. den
while(true)
Fall).quelle
Der Compiler ist klug genug, um herauszufinden, dass Ihre
while
Schleife unendlich ist.Der Compiler kann also nicht für Sie denken. Es kann nicht erraten, warum Sie diesen Code geschrieben haben. Gleiches gilt für die Rückgabewerte von Methoden. Java wird sich nicht beschweren, wenn Sie mit den Rückgabewerten der Methode nichts anfangen.
Um Ihre Frage zu beantworten:
Der Compiler analysiert Ihren Code und nachdem er herausgefunden hat, dass kein Ausführungspfad dazu führt, dass das Ende der Funktion abfällt, endet er mit OK.
Es kann legitime Gründe für eine Endlosschleife geben. Beispielsweise verwenden viele Apps eine Endlosschleife. Ein weiteres Beispiel ist ein Webserver, der auf unbestimmte Zeit auf Anforderungen warten kann.
quelle
In der Typentheorie gibt es so etwas wie den unteren Typ, der eine Unterklasse jedes anderen Typs (!) Ist und unter anderem verwendet wird, um die Nichtbeendigung anzuzeigen. (Ausnahmen können als eine Art Nichtbeendigung gelten - Sie beenden nicht über den normalen Pfad.)
Aus theoretischer Sicht kann davon ausgegangen werden, dass diese nicht terminierenden Anweisungen etwas vom Bottom-Typ zurückgeben, das ein Subtyp von int ist. Sie erhalten also (irgendwie) Ihren Rückgabewert schließlich aus einer Typperspektive. Und es ist vollkommen in Ordnung, dass es keinen Sinn macht, dass ein Typ eine Unterklasse von allem anderen sein kann, einschließlich int, weil Sie nie einen zurückgeben.
In jedem Fall erkennen Compiler (Compiler-Writer) über die explizite Typentheorie oder nicht, dass es dumm ist, nach einer nicht abschließenden Anweisung nach einem Rückgabewert zu fragen: Es gibt keinen möglichen Fall, in dem Sie diesen Wert benötigen könnten. (Es kann schön sein, wenn Ihr Compiler Sie warnt, wenn er weiß, dass etwas nicht beendet wird, aber es sieht so aus, als ob Sie möchten, dass es etwas zurückgibt. Aber das ist besser für Stilprüfer a la lint, da Sie möglicherweise die Typensignatur benötigen, die Weg aus einem anderen Grund (z. B. Unterklassen), aber Sie wollen wirklich keine Kündigung.)
quelle
Es gibt keine Situation, in der die Funktion ihr Ende erreichen kann, ohne einen geeigneten Wert zurückzugeben. Daher gibt es für den Compiler nichts zu beanstanden.
quelle
Visual Studio verfügt über die Smart Engine, die erkennt, ob Sie einen Rückgabetyp eingegeben haben. In der Funktion / Methode sollte eine return-Anweisung enthalten sein.
Wie in PHP Ihr Rückgabetyp ist wahr, wenn Sie nichts zurückgegeben haben. Der Compiler erhält 1, wenn nichts zurückgegeben wurde.
Ab diesem Zeitpunkt
Der Compiler weiß, dass die Anweisung selbst unendlich ist, um sie nicht zu berücksichtigen. und der PHP-Compiler wird automatisch wahr, wenn Sie eine Bedingung in Ausdruck von while schreiben.
Bei VS wird jedoch kein Fehler im Stapel zurückgegeben.
quelle
Ihre while-Schleife wird für immer laufen und daher währenddessen nicht nach draußen kommen. es wird weiterhin ausgeführt. Daher ist der äußere Teil von while {} nicht erreichbar und es macht keinen Sinn, eine Rückgabe zu schreiben oder nicht. Der Compiler ist intelligent genug, um herauszufinden, welcher Teil erreichbar ist und welcher nicht.
Beispiel:
Der obige Code wird nicht kompiliert, da der Wert der Variablen x im Hauptteil der while-Schleife geändert werden kann. Dies macht den äußeren Teil der while-Schleife erreichbar! Und daher wird der Compiler den Fehler "Keine Rückgabeanweisung gefunden" auslösen.
Der Compiler ist nicht intelligent genug (oder eher faul;)), um herauszufinden, ob der Wert von x geändert wird oder nicht. Hoffe das klärt alles.
quelle
int x = 1; while(x * 0 == 0) { ... }
es sich um eine Endlosschleife handelt. Die Spezifikation besagt jedoch, dass der Compiler nur dann Steuerflussabzüge vornehmen sollte, wenn der Schleifenausdruck konstant ist , und die Spezifikation definiert einen konstanten Ausdruck so , dass er keine Variablen enthält . Der Compiler war daher zu schlau . In C # 3 habe ich den Compiler an die Spezifikation angepasst, und seitdem sind diese Ausdrücke absichtlich weniger klug."Warum warnt der Compiler nicht einmal davor, etwas zurückzugeben? Oder warum erlaubt uns eine Sprache, eine nicht leere Methode mit einer Endlosschleife zu haben und nichts zurückzugeben?"
Dieser Code ist auch in allen anderen Sprachen gültig (wahrscheinlich außer Haskell!). Weil die erste Annahme ist, dass wir "absichtlich" Code schreiben.
Und es gibt Situationen, in denen dieser Code vollständig gültig sein kann, beispielsweise wenn Sie ihn als Thread verwenden. oder wenn a zurückgegeben wird
Task<int>
, können Sie eine Fehlerprüfung basierend auf dem zurückgegebenen int-Wert durchführen, der nicht zurückgegeben werden sollte.quelle
Ich kann mich irren, aber einige Debugger erlauben das Ändern von Variablen. Während x nicht durch Code geändert wird und durch JIT optimiert wird, kann man x in false ändern und die Methode sollte etwas zurückgeben (wenn dies vom C # -Debugger zugelassen wird).
quelle
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 .
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:Wenn die
while
Anweisung normal ausgeführt werden kann , ist eine folgende return-Anweisung erforderlich, da der Code als erreichbar angesehen wird und jedewhile
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 ohnebreak
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:
Mit:
Der Grund für die Unterscheidung ist sehr interessant und beruht auf dem Wunsch, bedingte Kompilierungsflags zuzulassen, die keine Compilerfehler verursachen (vom JLS):
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.quelle