Endlosschleife unterbricht die Methodensignatur ohne Kompilierungsfehler [duplicate]

Lesezeit: 4 Minuten

Benutzer-Avatar
Simo Martomaa

Ich frage mich, warum der folgende Code in Java zulässig ist, ohne dass ein Kompilierungsfehler auftritt. Meiner Meinung nach bricht dieser Code die Methodensignatur, indem er keine zurückgibt String. Könnte mir jemand erklären, was ich hier vermisse?

public class Loop {

  private String withoutReturnStatement() {
    while(true) {}
  }

  public static void main(String[] a) {
    new Loop().withoutReturnStatement();
  }
}

  • Weil der Compiler schlauer ist als Sie denken und sehen, dass die Funktion nicht zurückkehrt?

    – Irgendein Programmierer-Typ

    6. August 2014 um 7:26 Uhr

  • Es ist nicht nur eine interessante Frage, sondern auch eine hot network question 😀

    – Suresh Atta

    6. August 2014 um 8:31 Uhr

  • @sᴜʀᴇsʜᴀᴛᴛᴀ: und beantwortet von Jon Skeet…

    – PlasmaHH

    6. August 2014 um 9:14 Uhr

  • gute Frage… und zu meiner Überraschung gilt das auch für C#

    – Marcel B

    6. August 2014 um 11:32 Uhr

  • Die Antwort von @ JonSkeet ist zwar großartig, aber ich denke, sie betont nicht den grundlegenden Punkt: Der Rückgabetyp in einer Methodensignatur ist kein Versprechen, dass die Methode schließlich ein Objekt dieses Typs zurückgeben wird (ein solches Versprechen wäre unmöglich für die Compiler aufgrund der Nicht-Berechenbarkeit des Halteproblems zu überprüfen), sondern es ist eher ein Versprechen, dass Wenn die Methode zurückkehrt, ist der zurückgegebene Wert von diesem Typ.

    – Jules

    7. August 2014 um 6:16 Uhr

Benutzer-Avatar
Jon Skeet

Der endgültige } der Methode ist nicht erreichbar – Sie erhalten nur dann einen Kompilierungsfehler, wenn es möglich ist, zum Ende der Methode zu gelangen, ohne einen Wert zurückzugeben.

Dies ist nützlicher für Fälle, in denen das Ende der Methode aufgrund einer Ausnahme nicht erreichbar ist, z

private String find(int minLength) {
    for (String string : strings) {
        if (string.length() >= minLength) {
            return string;
        }
    }
    throw new SomeExceptionIndicatingTheProblem("...");
}

Die Regel dazu steht in der JLS-Abschnitt 8.4.7:

Wenn eine Methode mit einem Rückgabetyp deklariert wird (§8.4.5), tritt ein Kompilierzeitfehler auf, wenn der Hauptteil der Methode normal abgeschlossen werden kann (§14.1).

Ihre Methode kann nicht normal abgeschlossen werden, daher liegt kein Fehler vor. Wichtig ist, dass es nicht nur nicht normal abgeschlossen werden kann, sondern auch die Spezifikation erkennt dass es nicht normal abgeschlossen werden kann. Aus JLS 14.21:

EIN while Anweisung kann normal abgeschlossen werden, wenn mindestens eine der folgenden Aussagen zutrifft:

  • Das while -Anweisung erreichbar ist und der Bedingungsausdruck kein konstanter Ausdruck (§15.28) mit Wert ist true.
  • Es ist erreichbar break Anweisung, die die verlässt while Aussage.

In Ihrem Fall der Bedingungsausdruck ist eine Konstante mit Wert trueund es gibt keine break Anweisungen (erreichbar oder anderweitig) so die while Anweisung kann nicht normal abgeschlossen werden.

  • Das Auslösen der Ausnahme ist sinnvoll. Das Überraschende daran ist while(true) {} “zählt”. Besonders aus einer Sprache, die sich nicht einmal kompilieren lässt, ist bekannt, dass es unerreichbaren Code gibt.

    – Paul Tucher

    6. August 2014 um 15:18 Uhr


  • @PaulDraper: Ich bin mir nicht sicher, was du meinst. In beiden Fällen (Endlosschleife und Ausnahme) können Sie das Ende der Methode nicht normal erreichen, sodass Sie nicht zurückkehren müssen. Sagen Sie es so – wenn Sie tat haben eine return Aussage am Ende, das wäre unerreichbar … nicht gut.

    – Jon Skeet

    6. August 2014 um 15:19 Uhr

  • Ich sollte klarer sein. Die Antwort ist 100% richtig, und while(1) {} passt zu dem von dir angegebenen JLS. Ich bin nur überrascht, dass sie sich dafür entschieden haben, es auf diese Weise zu entwerfen, und die Implementierer sich dafür entschieden haben, die Bedingungen von zu inspizieren while Schleifen. Es ist ein Halteproblem, ein verlorener Kampf. while(1) {} kompiliert, aber while("foo".length() > 0) {} nicht kompiliert, zumindest nicht mit OpenJDK 7. Jetzt könnte ein anderer Java-Compiler ausgefeilter sein und diesen Fall erkennen. Plötzlich ist Ihr Write-Once-Run-Everywhere-Code kaputt.

    – Paul Tucher

    6. August 2014 um 15:30 Uhr

  • @PaulDraper: Nein, ein Compiler könnte nicht wählen Sie, anspruchsvoller zu sein. Die Sprachspezifikation ist ziemlich klar in Bezug auf die Erreichbarkeit. „Eine while-Anweisung kann normal abgeschlossen werden, wenn mindestens eine der folgenden Aussagen wahr ist: Die while-Anweisung ist erreichbar und der Bedingungsausdruck ist kein konstanter Ausdruck (§15.28) mit dem Wert true. […]”. "foo".length() > 0 ist kein konstanter Ausdruck. Java versucht nicht, das Halteproblem zu lösen – es definiert nur einige klare Regeln, welche Compiler welcher Adresse a folgen müssen Sehr wenig Situationen, in denen das Ergebnis zur Kompilierzeit sicher bekannt ist.

    – Jon Skeet

    6. August 2014 um 15:33 Uhr


  • @StephenChung: Beachten Sie, dass der Begriff “konstanter Ausdruck” von der JLS gut definiert ist (§15.28), sodass sich jeder konforme Compiler gleich verhalten muss. Zum Beispiel bool foo=true; while(foo){} würde eine return-Anweisung als erfordern foo bezieht sich nicht auf einen konstanten Ausdruck, wie er von JLS angegeben wird. Jedoch final bool foo=true; while(foo){} erlaubt keine Rückgabe als foo ist in diesem Fall ein konstanter Ausdruck.

    – Sieg

    15. August 2014 um 18:32 Uhr

Benutzer-Avatar
Ruchira Gayan Ranaweera

 private String withoutReturnStatement() {
    while(true) {
        // you will never come out from this loop
     } // so there will be no return value needed
    // never reach here ===> compiler not expecting a return value
  }  

Zur weiteren Klärung versuchen Sie dies

private String withoutReturnStatement() {
    while(true) {}
    return ""; // unreachable
}

Es sagt unreachable Aussage

  • Es wäre viel sinnvoller gewesen, auch auf die JLS hinzuweisen.

    – asynchron

    6. August 2014 um 7:35 Uhr

  • +1 für den zweiten Teil Ihrer Antwort. Das macht es sehr deutlich.

    – Suresh Atta

    6. August 2014 um 7:39 Uhr

1382340cookie-checkEndlosschleife unterbricht die Methodensignatur ohne Kompilierungsfehler [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy