Blog

Bitte schließen Sie die Ressource hinter sich.

Lars Vonk

Aktualisiert Oktober 23, 2025
4 Minuten

Wie man Ressourcen schließt, ist keine Raketenwissenschaft. Dennoch sehe ich in vielen Projekten, auch in meinem eigenen, dass Ressourcen nicht richtig geschlossen werden. Meistens wird vergessen, die Ressourcen in einem Finally-Block zu schließen, oder es wird vergessen, dass das Schließen einer Ressource auch eine Exception auslösen kann, was zu einer Exception-Verschluckung führen kann. In Java 5 wurde die Schnittstelle Closable eingeführt, die einige bequeme Möglichkeiten für das Schließen von Ressourcen bietet. Sehen wir uns ein Beispiel an, das ich in diesem Blog verwenden werde, um zu zeigen, welche Probleme beim Umgang mit Ressourcen auftreten können und wie wir den Beispielcode so umgestalten können, dass er die verwendete Ressource sicher schließt.

public void readFile() throws IOException {
  BufferedReader reader = null;
  versuchen {
  reader = new BufferedReader(new FileReader("foo.txt"));
  String line = null;
  while((line = reader.readLine()) != null) {
  String formattedLine = Parser.parseLine(line);
  // andere Dinge tun
  }
  } finally {
  reader.close();
  }
}

Obwohl sich der Aufruf von reader.close() in einem finally-Block befindet, ist mit diesem Code noch etwas nicht in Ordnung. Nehmen wir an, Parser.parseLine(line) löst eine RuntimeException aus. Wie Sie wissen (sollten), ist es auch möglich, dass reader.close() eine IOException auslöst. Wenn beide Methoden Exceptions auslösen, verlieren wir die RuntimeException, die von Parser.parseLine(line) ausgelöst wurde, und wir werden nie den wahren Grund für das Scheitern unseres Codes erfahren. Dieses Phänomen wird als "Exception swallowing" bezeichnet, was eine schlechte Sache ist (ich werde nicht weiter auf dieses Thema eingehen). Wir können unseren Code so umgestalten, dass wir die ursprüngliche Ausnahme nicht verschlucken:

public void copyFile() throws IOException {
  BufferedReader reader = null;
  versuchen {
  reader = new BufferedReader(new FileReader("foo.txt"));
  String line = null;
  while((line = reader.readLine()) != null) {
  String formattedLine = Parser.parseLine(line);
  // andere Dinge tun
  }
  } finally {
  versuchen {
  reader.close();
  } catch(IOException e) {
  log.info("Leser schließen fehlgeschlagen.", e);
  }
  }

Dieser Code ist jetzt sicher vor dem Verschlucken von Ausnahmen und schließt die verwendeten Ressourcen, aber er sieht für mich hässlich aus. Ich mag den verschachtelten try-catch-Block nicht. Wenn wir mehr als eine Ressource schließen müssen, wird es noch schlimmer, da wir so viele verschachtelte try-catch-Blöcke benötigen, wie es Ressourcen gibt. Schauen wir mal, ob wir noch etwas mehr refaktorisieren können. Wie ich bereits sagte, implementieren seit Java 5 alle Ressourcen, die geschlossen werden können, die Schnittstelle Closeable. Dies gibt uns die Möglichkeit, eine Utility-Methode zu erstellen, die das Schließen von Ressourcen übernimmt und das Verschlucken von Ausnahmen verhindert. Nach der Umstrukturierung sieht der Code wie folgt aus:

public void copyFile() throws IOException {
  BufferedReader reader = null;
  versuchen {
  reader = new BufferedReader(new FileReader("foo.txt"));
  String line = null;
  while((line = reader.readLine()) != null) {
  String formattedLine = Parser.parseLine(line);
  // andere Dinge tun
  }
  } finally {
  close(reader);
  }
}
private void close(Closeable closeable) {
  versuchen {
  if(closeable != null) {
  closeable.close();
  }
  } catch(IOException e) {
  log.info("Leser schließen fehlgeschlagen.", e);
  }
}

Wir können die Methode close(Closeable) für jede Closeable-Ressource verwenden, die wir in unserem Code schließen müssen. Wenn wir mehr als eine Ressource in der Methode haben, reicht ein einfacher Aufruf von close(Closeable) im finally-Block aus. Der große Vorteil dieses Ansatzes besteht darin, dass Ihre "Haupt"-Methode lesbar bleibt und die Implementierung des Schließens von Ressourcen an einer Stelle erfolgt.Es gibt jedoch noch ein Problem mit diesem Ansatz: Es kann vorkommen, dass man vergisst, den Aufruf der close(Closeable) -Methode in einen finally-Block zu setzen oder die close(Closeable) -Methode überhaupt aufzurufen.Eine Lösung für dieses Problem ist die Verwendung des Template-Musters. Beliebte Frameworks wie das Spring-Framework machen häufig Gebrauch vom Template-Muster. Beispiele dafür sind das HibernateTemplate, JdbcTemplate und viele andere. Wenn wir diesen Ansatz verwenden, können wir sicher sein, dass die Ressourcen immer ordnungsgemäß in einem finally-Block geschlossen werden. Eine Implementierung eines solchen Template-Musters könnte wie folgt aussehen:

public class CloseableTemplate {
  public void execute(CloseableCallbackHandler callbackHandler, T closeable) {
  versuchen {
  callbackHandler.doWithCloseable(closeable);
  } finally {
  close(closeable);
  }
  }
  private void close(Closeable closeable) {
  versuchen {
  if(closeable != null) {
  closeable.close();
  }
  } catch(IOException e) {
  log.info("Leser schließen fehlgeschlagen.", e);
  }
  }
}
public interface CloseableCallbackHandler {
  void doWithCloseable(T closeable);
}

Die Implementierung der copyFile-Methode würde dann wie folgt aussehen:

public void copyFile() throws IOException {
  BufferedReader reader = new BufferedReader(new FileReader("foo.txt"));
  new CloseableTemplate().execute(
  new CloseableCallbackHandler(){
  @Override
  public void doWithCloseable(BufferedReader bufferedReader) {
  String line = null;
  while((line = reader.readLine()) != null) {
  String formattedLine = Parser.parseLine(line);
  // andere Dinge tun
  }
  }
  }, bufferedReader);
  }
}

Wie Sie sehen können, ist der try-finally-Block in der copyFile-Methode nicht mehr notwendig, da das CloseableTemplate dies übernimmt. Wenn Sie also sicher sein wollen, dass die Ressourcen geschlossen sind, schlage ich vor, dass Sie einen ähnlichen Ansatz in Ihrem Projekt verwenden. Lars

Verfasst von

Lars Vonk

Contact

Let’s discuss how we can support your journey.