Frage

Ich war kürzlich überrascht, als ich herausfand, dass es in Java möglich ist, eine Return-Anweisung in einem Final-Block zu haben.

Es scheint, als ob viele Leute denken, dass es eine schlechte Sache ist, so zu handeln, wie es in „Kehren Sie nicht in einer Final-Klausel zurück'.Als ich etwas tiefer kratzte, fand ich auch „Die Rückkehr von Java ist nicht immer der Fall', das einige ziemlich schreckliche Beispiele für andere Arten der Flusskontrolle in „finally“-Blöcken zeigt.

Meine Frage ist also: Kann mir jemand ein Beispiel geben, bei dem eine Return-Anweisung (oder eine andere Flusskontrolle) in einem „finally“-Block besseren/besser lesbaren Code erzeugt?

War es hilfreich?

Lösung

Die Beispiele, die Sie angeführt haben, sind Grund genug dafür nicht Verwenden Sie die Flusskontrolle von „finally“.

Auch wenn es ein erfundenes Beispiel gibt, bei dem es „besser“ ist, denken Sie an den Entwickler, der Ihren Code später pflegen muss und sich der Feinheiten möglicherweise nicht bewusst ist.Dieser arme Entwickler könnte sogar Sie sein ...

Andere Tipps

Es fiel mir WIRKLICH schwer, vor Jahren einen Fehler aufzuspüren, der dadurch verursacht wurde.Der Code war etwa so:

Object problemMethod() {
    Object rtn = null;
    try {
        rtn = somethingThatThrewAnException();
    }
    finally {
        doSomeCleanup();
        return rtn;
    }
}

Was passiert ist, ist, dass die Ausnahme in einem anderen Code ausgelöst wurde.Es wurde gefangen, protokolliert und innerhalb des wieder geworfen somethingThatThrewAnException() Methode.Aber die Ausnahme wurde nicht weiter verbreitet problemMethod().Nachdem wir uns das lange angeschaut hatten, haben wir es endlich auf die Return-Methode zurückgeführt.Die Return-Methode im „finally“-Block verhinderte grundsätzlich, dass sich die im try-Block aufgetretene Ausnahme weiter ausbreitete, obwohl sie nicht abgefangen wurde.

Wie andere bereits gesagt haben, ist es gemäß der Java-Spezifikation zwar legal, von einem endgültigen Block zurückzukehren, aber es ist eine SCHLECHTE Sache und sollte nicht getan werden.

javac warnt vor der Rückkehr in „finally“, wenn Sie -Xlint:finally verwenden.Ursprünglich gab Javac keine Warnungen aus – wenn etwas mit dem Code nicht stimmt, sollte die Kompilierung fehlschlagen.Leider bedeutet die Abwärtskompatibilität, dass unerwartete geniale Dummheiten nicht verhindert werden können.

Ausnahmen können von „finally“-Blöcken ausgelöst werden, aber in diesem Fall ist das gezeigte Verhalten mit ziemlicher Sicherheit das, was Sie wollen.

Das Hinzufügen von Kontrollstrukturen und Returns zu „finally{}“-Blöcken ist nur ein weiteres Beispiel für Missbräuche „nur weil man es kann“, die in nahezu allen Entwicklungssprachen verbreitet sind.Jason hatte Recht mit der Annahme, dass es leicht zu einem Wartungsalbtraum werden könnte – die Argumente gegen vorzeitige Rückgaben von Funktionen gelten umso mehr für diesen Fall der „späten Rückgabe“.

Schließlich gibt es Blöcke für einen einzigen Zweck: Sie sollen es Ihnen ermöglichen, alles selbst in Ordnung zu bringen, unabhängig davon, was im vorangegangenen Code passiert ist.Im Wesentlichen geht es dabei um das Schließen/Freigeben von Dateizeigern, Datenbankverbindungen usw., obwohl ich mir vorstellen kann, dass es überdehnt wird, wenn man sagen möchte, dass es eine maßgeschneiderte Prüfung hinzufügt.

Alles, was die Rückgabe der Funktion beeinflusst, sollte im try{}-Block liegen.Selbst wenn Sie eine Methode hätten, bei der Sie einen externen Status überprüften, eine zeitaufwändige Operation durchführten und diesen Status dann erneut überprüften, falls er ungültig wurde, würden Sie die zweite Prüfung immer noch innerhalb des try{} wünschen – wenn er schließlich drinnen wäre{} und der lange Vorgang fehlschlägt, würden Sie diesen Zustand dann unnötigerweise ein zweites Mal überprüfen.

Ein einfacher Groovy-Test:

public class Instance {

  List<String> runningThreads = new ArrayList<String>()

  void test(boolean returnInFinally) {

    println "\ntest(returnInFinally: $returnInFinally)"
    println "--------------------------------------------------------------------------"
    println "before execute"
    String result = execute(returnInFinally, false)
    println "after execute -> result: " + result
    println "--------------------------------------------------------------------------"

    println "before execute"
    try {
      result = execute(returnInFinally, true)
      println "after execute -> result: " + result
    } catch (Exception ex) {
      println "execute threw exception: " + ex.getMessage()
    }  
    println "--------------------------------------------------------------------------\n"

  }

  String execute(boolean returnInFinally, boolean throwError) {
      String thread = Thread.currentThread().getName()
      println "...execute(returnInFinally: $returnInFinally, throwError: $throwError) - thread: $thread"
      runningThreads.add(thread)
      try {
        if (throwError) {
          println "...error in execute, throw exception"
          throw new Exception("as you liked :-)")
        }
        println "...return 'OK' from execute"
        return "OK"
      } finally {
        println "...pass finally block"
        if (returnInFinally) return "return value from FINALLY ^^"
        // runningThreads.remove(thread)
      }
  }
}

Instance instance = new Instance()
instance.test(false)
instance.test(true)

Ausgabe:

test(returnInFinally: false)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: OK
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: false, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
execute threw exception: as you liked :-)
-----------------------------------------------------------------------------


test(returnInFinally: true)
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: false) - thread: Thread-116
...return 'OK' from execute
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------
before execute
...execute(returnInFinally: true, throwError: true) - thread: Thread-116
...error in execute, throw exception
...pass finally block
after execute -> result: return value from FINALLY ^^
-----------------------------------------------------------------------------

Frage:

Ein interessanter Punkt für mich war zu sehen, wie Groovy mit impliziten Renditen umgeht.In Groovy ist es möglich, von einer Methode „zurückzukehren“, indem man am Ende einfach einen Wert hinterlässt (ohne Rückgabe).Was passiert Ihrer Meinung nach, wenn Sie den Kommentar entfernen? runningThreads.remove(..) Zeile in der final-Anweisung – überschreibt dies den regulären Rückgabewert („OK“) und deckt die Ausnahme ab?!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top