Wozu try-catch-finally?

Endlich habe ich Zeit gehabt, mich etwas mit “finally” von Java zu beschäftigen (sprich: Internet bemüht, ausprobiert), hab’ ich mich doch schon öfter gefragt, wozu man das braucht.

Anwendungsbeispiel: ein Datenstrom soll geöffnet, gelesen und geschlossen werden. Dabei können IO-Fehler (und andere Fehler) auftreten, die abgefangen werden sollen. Tritt ein Fehler auf, soll der Strom geschlossen werden. Bisher habe ich das so programmiert:

InputStream stmIn = null;
try {
  stmIn = new InputStream(...);
  stmIn.read();
  stmIn.close();
} catch (Exception e) {
  e.printStackTrace();
  if (stmIn != null) {
    try {
      stmIn.close();
    } catch (Exception e) {
      // ignorieren
    }
  }
}

oder auch so:

InputStream stmIn = null;
try {
  stmIn = new InputStream(...);
  stmIn.read();
  stmIn.close();
} catch (Exception e) {
  e.printStackTrace();
}
if (stmIn != null) {
  try {
    stmIn.close();
  } catch (Exception e) {
    // ignorieren
  }
}

Beide Lösungen haben zwei Nachteile: Erstens muss ich den InputStream vor dem try definieren, damit ich ihn im catch oder danach schließen kann. Zweitens rufe ich zweimal close auf, bei jeder Codeänderung ist das ein potentieller Fehlerfall.

Mein bisheriges Verständnis von finally führte dann zu folgendem Code:

InputStream stmIn = null;
try {
  stmIn = new InputStream(...);
  stmIn.read();
} catch (Exception e) {
  e.printStackTrace();
} finally {
  if (stmIn != null) {
    try {
      stmIn.close();
    } catch (Exception e) {
      // ignorieren
    }
  }
}

Immerhin ein close eingespart, aber elegant ist das noch nicht und das erste Problem ist noch nicht gelöst. Nach dem ausgiebigen Webseitenstudium präferiere ich folgende Lösung:

try {
  InputStream stmIn = null;
  try {
    stmIn = new InputStream(...);
    stmIn.read();
  } finally {
    stmIn.close();
  }
} catch (Exception e) {
  e.printStackTrace();
}

Das ist jetzt elegant. das erste try sorgt für die Verarbeitung der Exceptions, die auf jeden Fall abgearbeitet werden, da das zweite try keinen catch-Block hat. Das zweite try sorgt aber dafür, dass der Datenstrom auf jeden Fall geschlossen wird. Fehler beim Schließen werden ebenfalls abgefangen. Außerhalb des ersten try-catch-Blocks ist der Datenstrom nicht sichtbar, die Variablenkapselung funktioniert.

Update (7.2.10): die Code-Formatierung war komplett daneben, komplett erneuert.

Update 2 (7.2.10): die Formatierung der Webseite zeigt jetzt den Code an 🙂

6 thoughts on “Wozu try-catch-finally?”

  1. ist das nur bei mir so oder warum ist in den Boxen weiße Schrift auf weißem Hintergrund?
    Ähnliches Problem übrigens auch bei der Box rechts names “Abonnieren”: Schwarze Schrift auf sehr sehr dunkelblauem Hintergrund.
    Das ganze übrigens bei Firefox 3.6

  2. Wenn nun aber eine Exception während der Instanzierung auftritt, tritt beim Versuch, den Stream zu schließen, auf jeden Fall noch eine NullPointerException auf, und die ursprüngliche Exception wird verworfen. Das macht den Stacktrace unbrauchbar. Also fände ich es trotzdem sinnvoll, vor dem Schließen zu prüfen, ob überhaupt ein Stream existiert. Aber auch dann ist natürlich nicht garantiert, dass keine weitere Exception auftritt. Daher ziehe ich die vorherige, unelegante Lösung vor und würde dabei vorsichtshalber noch die eventuelle Exception loggen, die beim Schließen auftritt. Falls man sich nichts aus den Fehlermeldungen macht, kann man natürlich getrost die letzte, kompakte Version verwenden.

  3. Stimmt, auf null prüfen ist da nicht verkehrt.

    Hmmm. Ich würde weiter die letzte Variante nehmen, ergänzt um null-Check. Da schwirren nicht so viele ungenutzte Variablen rum 🙂

Leave a Reply

Your email address will not be published.

67 − = 60