2015-06-22 7 views
63

Dies war ein Interview Frage:Mehrere return-Anweisungen ohne Compiler-Fehler

public class Demo { 

    public static void main(String[] args) { 
     System.out.println(foo()); 
    } 

    static String foo() { 
     try { 
      return "try ..."; 
     } catch (Exception e) { 
      return "catch ..."; 
     } finally { 
      return "finally ..."; //got as result 
     } 
    } 
} 

Meine Frage ist, warum gibt es keine Kompilierung Fehler. Wenn ich die Return-Anweisung in meinem finally Block habe, ist es verpflichtet, von finally anstelle von try und catch Block zurückzukehren. Ich habe versucht, diesen Code mit -Xlint Option zu kompilieren, gibt es eine Warnung als.

warning: [finally] finally clause cannot complete normally 
+32

Welche Sprache in der Java-Spezifikation glauben Sie, dass das bricht, das würde einen Fehler erfordern? –

Antwort

76

Es ist kein Übersetzungsfehler geben, weil es von der Java Language Specification erlaubt ist. Es gibt jedoch eine Warnmeldung, da eine return-Anweisung im finally-Block eine schlechte Idee ist.

In Ihrem Beispiel geschieht Folgendes. Die return Anweisung im try Block wird ausgeführt. Der finally-Block muss jedoch immer ausgeführt werden, damit er ausgeführt wird, nachdem der catch-Block abgeschlossen ist. Die dort auftretende return-Anweisung überschreibt das Ergebnis der vorherigen return-Anweisung, und die Methode gibt das zweite Ergebnis zurück.

Ebenso sollte ein finally Block in der Regel keine Ausnahme auslösen. Deshalb besagt die Warnung, dass der finally Block normal beendet werden sollte, dh ohne return oder eine Ausnahme auszulösen.

+2

Ausgezeichnete Antwort! Gute Erklärung und klares Beispiel. Besser als nur Spezifikationen zu zitieren – higuaro

10

Es gibt keine Kompilierung Fehler, da nur 1 und genau 1 von return Anweisung wird die Steuerung tatsächlich wieder zurück Code zu rufen.

Wie erklärt @Hoopje, return innerhalb try oder catch wird zuerst ausgeführt, ihre jeweilige Return-Anweisung wird auch ausgeführt. Aber kurz bevor das Steuerelement wieder an den aufrufenden Code zurückgegeben wird, wird der Block finally ausgeführt. Nun, diese block auch return s etwas, so dass diese Rückkehr die vorherige überschreibt.

+2

Das ist eigentlich nicht wahr. Zwei Return-Anweisungen werden ausgeführt, aber die zweite überschreibt die erste. – Hoopje

+0

Oh. Ich wusste nichts davon. Bitte geben Sie mir einen Hinweis, damit ich etwas darüber erfahren kann. – Aakash

+0

Nun, Sie könnten es selbst ausprobieren, indem Sie keine Konstante verwenden, sondern eine Funktion, die etwas als Argument ausgibt. Sie werden sehen, dass das Argument der beiden return-Anweisungen ausgewertet wird. – Hoopje

5

Ihr Code funktioniert gut, weil es in try, catch und finally blocks nur eine return-Anweisung gibt. Der Kompilierungsfehler tritt auf, wenn Sie versuchen, zwei return-Anweisungen innerhalb eines der Blöcke try, catch oder finally zu schreiben, die sagen, dass es eine nicht erreichbare return-Anweisung gibt.

8

Brilliant Question .. Nach meiner Kenntnis wird Return-Anweisung des Try and Catch-Blocks übertragen, um schließlich, wenn Sie Ihren Code endgültig Block hinzugefügt haben. So funktioniert es.

In diesem Fall werden alle Codezeilen ausgeführt und Sie können versuchen, zu debuggen. Die drei Blöcke, die ich probiert habe, codieren.

public class Main { 

    public static void main(String[] args) { 
     System.out.println(foo()); 
    } 
    static String foo() { 
     try { 
      throw new Exception(); 
     } catch (Exception e) { 
      return "catch ..."; 
     } finally { 
      return "finally ..."; //got as result 
     } 
    } 
} 

Sie können die Idee von unten Link bekommen. Multiple returns: Which one sets the final return value?

8

Es ist im Wesentlichen die gleiche wie folgt aus:

public boolean someMethod(){ 
     if(1 == 1){ 
      return true; 
     } 
     return false; 
} 

Es wird kein Übersetzungsfehler geben, obwohl es eine Warnung geben. Der Compiler gibt nur dann einen Fehler aus, wenn eine keine Rückgabeanweisung ausgeführt werden kann.

39

in der Java Language Specification Dies wird beschrieben:

§14.17

Abrupte Abschluss einer finally-Klausel kann die Übertragung von Kontrolle stören durch eine return Anweisung eingeleitet.

§14.20.2

Wenn die Ausführung des try Block normalerweise abgeschlossen ist, dann wird der finally Block ausgeführt wird, und dann gibt es eine Wahl:

  • Wenn der finally Block normal abgeschlossen ist, dann wird die try-Anweisung normal abgeschlossen.
  • Wenn der Block finally abrupt zum Grund S abgeschlossen ist, dann wird die Anweisung abgeschlossen try abrupt zum Grund S.

Wenn die Ausführung des try Block vervollständigt abrupt aus irgendeinem anderen Grund R, dann wird der Block ausgeführt wird finally und dann gibt es eine Wahl:

  • Wenn der finally Block normal abgeschlossen ist, dann wird die try Anweisung abrupt Grund schließt R.
  • Wenn der finally-Block aus Gründen S abrupt beendet wird, wird die try-Anweisung aus Gründen S abrupt beendet (und Grund R wird verworfen).
4

(kurz die fett und kursiv Teile der Antwort Antwort- Lesen) Fluss

Die Ausführung gemäß den Java 8 docs. Es bietet Ihnen die Details. Sie können die Ausführung von Rückgabeanweisungen basierend auf dem Folgenden ableiten.

Eine try-Anweisung mit einem finally-Block wird ausgeführt, indem zuerst der try-Block ausgeführt wird.

Dann gibt es eine Auswahl:

• Wenn die Ausführung des try-Block normal abgeschlossen ist, dann wird der finally-Block ausgeführt wird, und dann gibt es eine Auswahl:

- Wenn der finally-Block normal abgeschlossen , dann wird die Testanweisung normalerweise abgeschlossen.

- Wenn der finally-Block abrupt Grund S abgeschlossen ist, dann wird die try-Anweisung beendet abrupt Grund S.

• Wenn die Ausführung des try-Block wegen eines Wurfes eines Wertes V abrupt beendet ist, dann gibt es eine Auswahl:

- Wenn der Laufzeittyp von V Zuordnung kompatibel mit einer abfangbare Ausnahme Klasse jeder catch-Klausel der try-Anweisung, dann der erste (ganz links), so catch-Klausel ausgewählt ist. Der Wert V wird dem Parameter der ausgewählten catch-Klausel zugewiesen, und die Klausel Block of that catch wird ausgeführt.

Dann gibt es eine Auswahl:

> Wenn der catch-Block normal abgeschlossen ist, dann wird der finally-Block ausgeführt wird. Dann gibt es eine Auswahl:

»Wenn der finally-Block normal abgeschlossen wird, wird die try-Anweisung normal abgeschlossen.

»Wenn der finally-Block aus irgendeinem Grund abrupt beendet wird, wird die try -Anweisung abrupt aus dem gleichen Grund beendet.

>Wenn der catch-Block aus Gründen R abrupt abgeschlossen wird, wird der finally-Block ausgeführt. Dann gibt es eine Auswahl:

»Wenn der finally-Block normal abgeschlossen ist, dann wird die try-Anweisung beendet abrupt Grund R.

» Wenn der finally-Block abrupt Grund S abgeschlossen ist, dann wird die versuchen Sie Anweisung abrupt aus Gründen S abgeschlossen (und Grund R wird verworfen).

- Wenn der Laufzeittyp von V ist nicht Zuordnung kompatibel mit einer abfangbare Ausnahmeklasse jeder catch-Klausel der try-Anweisung, dann der schließlich Block ausgeführt wird.

Dann gibt es eine Auswahl:

> Wenn der finally-Block normal abgeschlossen ist, dann wird die try-Anweisung vervollständigt abrupt wegen eines Einwurfs des Wertes V.

> Wenn der finally-Block abrupt beendet für Grund S, dann wird die try-Anweisung aus Gründen S abrupt beendet (und der Wert V wird verworfen und vergessen).

• Wenn die Ausführung des try-Block aus einem anderen Grund R abrupt beendet ist, dann wird der schließlich Block ausgeführt, und dann gibt es eine Wahl:

- Wenn der schließlich vervollständigt Block normal, dann die try-Anweisung schließt abrupt für Grund R.

- Wenn der finally-Block aus Gründen S abrupt abgeschlossen wird, dann wird die try-Anweisung aus Gründen S abrupt beendet (und der Grund R wird verworfen).

die Erklärung ist klar, in dieser Link- javaDoc

2

versuchen diese ausgeführt wird:

es drucken: 1, 2, 3 und dann eine Division durch Null werfen Exception

public class Demo { 
    public static void main(String[] args) { 
    System.out.println(foo()); 
    } 
    public static String print(int a){ 
    System.out.println(a); 
    return String.valueOf(a/0); 
    } 
    static String foo() { 
    try { 
     return print(1); 
    } catch (Exception e) { 
     return print(2); 
    } finally { 
     return print(3); 
    } 
    } 
} 
Verwandte Themen