Rheinwerk Computing < openbook >


 
Inhaltsverzeichnis
Materialien
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Arrays und ihre Anwendungen
5 Der Umgang mit Zeichenketten
6 Eigene Klassen schreiben
7 Objektorientierte Beziehungsfragen
8 Ausnahmen müssen sein
9 Geschachtelte Typen
10 Besondere Typen der Java SE
11 Generics<T>
12 Lambda-Ausdrücke und funktionale Programmierung
13 Architektur, Design und angewandte Objektorientierung
14 Java Platform Module System
15 Die Klassenbibliothek
16 Einführung in die nebenläufige Programmierung
17 Einführung in Datenstrukturen und Algorithmen
18 Einführung in grafische Oberflächen
19 Einführung in Dateien und Datenströme
20 Einführung ins Datenbankmanagement mit JDBC
21 Bits und Bytes, Mathematisches und Geld
22 Testen mit JUnit
23 Die Werkzeuge des JDK
A Java SE-Module und Paketübersicht
Stichwortverzeichnis


Download:

- Listings, ca. 2,7 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil8 Ausnahmen müssen sein
Pfeil8.1 Problembereiche einzäunen
Pfeil8.1.1 Exceptions in Java mit try und catch
Pfeil8.1.2 Geprüfte und ungeprüfte Ausnahmen
Pfeil8.2 Geprüfte Ausnahmen
Pfeil8.2.1 Letzte ausgeführte Java-Programme loggen
Pfeil8.2.2 try-catch-Behandlung
Pfeil8.2.3 throws im Methodenkopf angeben
Pfeil8.3 Ungeprüfte Ausnahmen (RuntimeException)
Pfeil8.3.1 Eine NumberFormatException fliegt
Pfeil8.3.2 Bekannte RuntimeException-Klassen
Pfeil8.3.3 Kann man abfangen, muss man aber nicht
Pfeil8.4 Gut gefangen
Pfeil8.4.1 Bitte nicht schlucken – leere catch-Blöcke
Pfeil8.4.2 Wiederholung abgebrochener Bereiche *
Pfeil8.4.3 Mehrere Ausnahmen auffangen
Pfeil8.4.4 Ablauf einer Ausnahmesituation
Pfeil8.4.5 Abschlussbehandlung mit finally
Pfeil8.5 Die Klassenhierarchie der Ausnahmen
Pfeil8.5.1 Eigenschaften des Exception-Objekts
Pfeil8.5.2 Basistyp Throwable
Pfeil8.5.3 Die Exception-Hierarchie
Pfeil8.5.4 Oberausnahmen auffangen
Pfeil8.5.5 Schon gefangen?
Pfeil8.5.6 Alles geht als Exception durch
Pfeil8.5.7 Zusammenfassen gleicher catch-Blöcke mit dem multi-catch
Pfeil8.6 Auslösen eigener Exceptions
Pfeil8.6.1 Mit throw Ausnahmen auslösen
Pfeil8.6.2 Vorhandene Runtime-Ausnahmetypen kennen und nutzen
Pfeil8.6.3 Parameter testen und gute Fehlermeldungen
Pfeil8.6.4 Neue Exception-Klassen deklarieren
Pfeil8.6.5 Eigene Ausnahmen als Unterklassen von Exception oder RuntimeException?
Pfeil8.6.6 Ausnahmen abfangen und weiterleiten *
Pfeil8.6.7 Aufruf-Stack von Ausnahmen verändern *
Pfeil8.6.8 Präzises rethrow *
Pfeil8.6.9 Geschachtelte Ausnahmen *
Pfeil8.7 Automatisches Ressourcen-Management (try mit Ressourcen)
Pfeil8.7.1 try mit Ressourcen
Pfeil8.7.2 Die Schnittstelle AutoCloseable
Pfeil8.7.3 Mehrere Ressourcen nutzen
Pfeil8.7.4 try mit Ressourcen auf null-Ressourcen
Pfeil8.7.5 Ausnahmen vom close()
Pfeil8.7.6 Unterdrückte Ausnahmen *
Pfeil8.8 Besonderheiten bei der Ausnahmebehandlung *
Pfeil8.8.1 Rückgabewerte bei ausgelösten Ausnahmen
Pfeil8.8.2 Ausnahmen und Rückgaben verschwinden – das Duo return und finally
Pfeil8.8.3 throws bei überschriebenen Methoden
Pfeil8.8.4 Nicht erreichbare catch-Klauseln
Pfeil8.9 Harte Fehler – Error *
Pfeil8.10 Assertions *
Pfeil8.10.1 Assertions in eigenen Programmen nutzen
Pfeil8.10.2 Assertions aktivieren und Laufzeit-Errors
Pfeil8.10.3 Assertions feiner aktivieren oder deaktivieren
Pfeil8.11 Zum Weiterlesen
 

Zum Seitenanfang

8.7    Automatisches Ressourcen-Management (try mit Ressourcen) Zur vorigen ÜberschriftZur nächsten Überschrift

Java hat eine automatische Speicherbereinigung, die nicht mehr referenzierte Objekte erkennt und ihren Speicher automatisch freigibt. Nun bezieht sich der Garbage-Collector aber ausschließlich auf Speicher, doch es gibt viele weitere Ressourcen:

  • Dateisystemressourcen von Dateien

  • Netzwerkressourcen wie Socket-Verbindungen

  • Datenbankverbindungen

  • nativ gebundene Ressourcen des Grafiksubsystems

  • Synchronisationsobjekte

Auch hier gilt es, nach getaner Arbeit aufzuräumen und Ressourcen freizugeben, etwa Dateien und Datenbankverbindungen zu schließen.

Mit dem try-catch-finally-Konstrukt haben wir gesehen, wie Ressourcen freizugeben sind. Doch es lässt sich auch ablesen, dass relativ viel Quellcode geschrieben werden muss und dass try-catch-finally drei Unfeinheiten hat:

  1. Soll eine Variable in finally zugänglich sein, muss sie außerhalb des try-Blocks deklariert werden, was ihr eine längere Sichtbarkeit als nötig gibt.

  2. Das Schließen der Ressourcen bringt oft ein zusätzliches try-catch mit sich.

  3. Eine im finally ausgelöste Ausnahme (etwa beim close()) überdeckt die im try-Block ausgelöste Ausnahme.

 

Zum Seitenanfang

8.7.1    try mit Ressourcen Zur vorigen ÜberschriftZur nächsten Überschrift

Um das Schließen von Ressourcen zu vereinfachen, gibt es eine besondere Form der try-Anweisung, die try mit Ressourcen heißt. Mit diesem Sprachkonstrukt lassen sich Ressourcentypen automatisch schließen, die die Schnittstelle java.lang.AutoCloseable implementieren. Ein-/Ausgabeklassen wie Scanner, InputStream und Writer implementieren diese Schnittstelle und können direkt verwendet werden. Weil try mit Ressourcen dem Automatic Resource Management dient, heißt der spezielle try-Block auch ARM-Block.

Gehen wir in die Praxis: Aus einer Datei soll mit einem Scanner die erste Zeile gelesen und ausgegeben werden. Nach dem Lesen soll der Scanner geschlossen werden. Die linke Seite von Tabelle 8.3 nutzt die spezielle Syntax, die rechte Seite ist im Prinzip die Übersetzung, allerdings noch etwas vereinfacht, wie wir später genauer sehen werden.

try mit Ressourcen

Vereinfachte ausgeschriebene Implementierung

InputStream in = ClassLoader.getSystemResourceAsStream( "EastOfJava.txt" );


try ( Scanner res = new Scanner( in ) ) {
{ 

Scanner res = new Scanner( in );

try {
System.out.println( res.nextLine() );
}
}

finally {

res.close();

}

}

Tabelle 8.3    Vereinfache Umsetzung von »try mit Ressourcen«

Bisher haben wir nach dem Schlüsselwort try direkt einen Block gesetzt, doch try mit Ressourcen nutzt eine eigene erweiterte Syntax: Nach dem try folgt statt des direkten {}-Blocks eine Ressourcenspezifikation in runden Klammern und dann erst der {}-Block, also try () {} statt try {}.

Die Ressourcenspezifikation besteht aus einem Satz runder Klammern und einer Liste von Ressourcen. Die Ressourcen sind finale Variablen vom Typ AutoCloseable, und genau diese werden später automatisch geschlossen. Die Variablen können mit einem Gleichheitszeichen direkt mit einem Ausdruck initialisiert werden, etwa mit einem Konstruktor- oder Methodenaufruf. Vor Java 9 war die Initialisierung zwingend. Der Einsatz von var ist erlaubt.

Die in dem try deklarierte lokale AutoCloseable-Variable ist nur in dem Block gültig und wird automatisch freigegeben, gleichgültig, ob der ARM-Block korrekt durchlaufen wurde oder ob es bei der Abarbeitung zu einer Ausnahme kam. Der Compiler fügt alle nötigen Prüfungen ein.

[»]  Hinweis

Wird auf einer Variablen, die vom Typ AutoCloseable ist, nicht close() aufgerufen oder wird sie nicht in einem try mit Ressourcen eingesetzt, gibt der Java-Compiler eine Warnung aus. Eclipse etwa meldet: »Resource leak: '<unassigned Closeable value>' is never closed«. Die Warnung verschwindet mit @SuppressWarnings("resource").

 

Zum Seitenanfang

8.7.2    Die Schnittstelle AutoCloseable Zur vorigen ÜberschriftZur nächsten Überschrift

Das try mit Ressourcen schließt Ressourcen vom Typ AutoCloseable. Daher wird es Zeit, sich diese Schnittstelle etwas genauer anzuschauen:

Listing 8.26    java/lang/AutoCloseable.java

package java.lang;



public interface AutoCloseable {

void close() throws Exception;

}

Anders als das übliche close() ist die Ausnahme deutlich allgemeiner mit Exception angegeben; die Ein-/Ausgabe-Klassen lösen beim Misslingen immer eine IOException aus, aber jede Klasse hat eigene Ausnahmetypen:

Typ

Signatur

java.io.Scanner

close() // ohne Ausnahme

javax.sound.sampled.Line

close() // ohne Ausnahme

java.io.Writer

close() throws IOException

java.sql.Connection

close() throws SQLException

Tabelle 8.4    Einige Typen, die »AutoCloseable« implementieren bzw. erweitern

Eine Unterklasse darf die Ausnahme bei throws weglassen. Das machen Klassen wie der Scanner, der bei den Methoden keine Ausnahme weiterleitet, sondern Ausnahmen intern abfängt und die letzte Ausnahme später über die Methode ioException() zugänglich macht.

AutoCloseable und Closeable

Auf den ersten Blick einleuchtend wäre es, die schon existierende Schnittstelle Closeable als Typ zu nutzen. Doch das hätte Nachteile: Die close()-Methode ist mit einem throws IOException deklariert, was bei einer allgemeinen automatischen Ressourcenfreigabe unpassend ist, wenn etwa ein Grafikobjekt bei der Freigabe eine IOException auslöst. Vielmehr ist der Weg andersherum: Closeable erweitert AutoCloseable, denn das Schließen von Ein-/Ausgabe-Ressourcen ist eine besondere Art, allgemeine Ressourcen zu schließen.

package java.io;



import java.io.IOException;



public interface Closeable extends AutoCloseable {

void close() throws IOException;

}

Wer ist AutoCloseable?

Da alle Klassen, die Closeable implementieren, auch automatisch vom Typ AutoCloseable sind, kommen schon einige Typen zusammen. Im Wesentlichen sind es aber Klassen aus dem java.io-Paket, wie Channel-, Reader-, Writer-Implementierungen, FileLock, XMLDecoder und noch ein paar Exoten wie URLClassLoader, ImageOutputStream. Auch Typen aus dem java.sql-Paket gehören zu den Nutznießern. Klassen aus dem Bereich Threading, wo etwa ein Lock wieder freigegeben werden könnte, oder Grafikanwendungen, bei denen der Grafikkontext wieder freigegeben werden muss, gehören nicht dazu.

[»]  Hinweis

Es gibt Ströme, die müssen offen bleiben. Das gilt etwa für System.in, einen vom System bereitgestellten InputStream. Auch wenn dieser in einen Scanner verpackt wird, wird ein close() auf dem Scanner zu einem close() auf dem InputStream, und ein erneutes Lesen aus System.in wird mit einem »java.io.IOException: Stream closed« quittiert. Ein try ( Scanner in = new Scanner(System.in) ) { } ist also keine gute Idee.

[+]  Tipp *

Es ist mit einem Trick möglich, auch Exemplare in einem try mit Ressourcen zu nutzen, die nicht vom Typ AutoCloseable sind. Ein Lambda-Ausdruck oder eine Methodenreferenz lassen sich nutzen, um eine beliebige Methode als close()-Methode einzusetzen. Ein ReentrantLock zum Beispiel ist eine Implementierung eines Lock, um bei nebenläufigen Zugriffen einen Bereich abzuschließen. lock() beginnt den Bereich, unlock() gibt ihn wieder frei. Das unlock() lässt sich über einen Lambda-Ausdruck als close()-Methode verkaufen.

ReentrantLock lock = new ReentrantLock();

try ( AutoCloseable unlock = lock::unlock ) { // oder () -> {lock.unlock();}

lock.lock();

}

System.out.println( lock.isLocked() ); // false

Ob dieser »Trick« sinnvoll ist oder nicht, ist eine andere Frage. Das try mit Ressourcen setzt auf jeden Fall das unlock() in einen internen finally-Block, der über die Konstruktion eingespart wird. Allerdings wird üblicherweise die Ressource im try-mit-Ressourcen-Block auch erst deklariert, was hier vorher gemacht werden muss. Außerdem ist die Variable unlock unnütz. Daher ist die Relevanz eher niedrig.

 

Zum Seitenanfang

8.7.3    Mehrere Ressourcen nutzen Zur vorigen ÜberschriftZur nächsten Überschrift

Unsere beiden Beispiele zeigen die Nutzung eines Ressourcentyps. Es sind aber auch mehrere Typen möglich, die ein Semikolon trennt:

try ( InputStream  in  = Files.newInputStream( srcPath );

OutputStream out = Files.newOutputStream( destPath ) ) {

...

}

Weiterhin ist es erlaubt, dass die nachfolgende Ressource auf die vorherige Ressource verweist, sodass geschachtelte Ströme möglich sind:

try ( InputStream fis = Files.newInputStream( srcPath );

InputStream bis = new BufferedInputStream( fis ) ) {

...

}

Dieses Modell findet oft bei Dekoratoren Anwendung.

[»]  Hinweis

Die Trennung erledigt ein Semikolon, und jedes Segment kann einen unterschiedlichen Typ deklarieren, etwa InputStream/OutputStream. Die Ressourcentypen müssen also nicht gleich sein, und auch wenn sie es sind, muss der Typ immer neu geschrieben werden, also etwa:

try ( InputStream in1 = ...; InputStream in2 = ... )

Es ist ungültig, Folgendes zu schreiben:

try ( InputStream in1 = ..., in2 = ... )    // inline image Compilerfehler

Am Schluss der Ressourcensammlung kann – muss aber nicht – ein Semikolon stehen, so wie auch bei Array-Initialisierungen zum Schluss ein Komma stehen kann:

int[] array = { 1, 2, };

// ^ Komma optional

try ( InputStream in = Files.newInputStream( path ); ) { ... }

// ^ Semikolon optional

try ( InputStream in = Files.newInputStream( src );

OutputStream out = Files.newOutputStream( dest ); ) { ... }

// ^ Semikolon optional

Ob das stilvoll ist, muss jeder selbst entscheiden – in der »Insel« steht kein unnützes Zeichen.

Reihenfolge beim Schließen

Die Ressourcen werden in der umgekehrten Reihenfolge geschlossen, wie sie geöffnet wurden.

[zB]  Beispiel

Zunächst wird in, dann out initialisiert. Zum Schluss wird out, danach in geschlossen.

try ( InputStream  in  = Files.newInputStream( srcPath );

OutputStream out = Files.newOutputStream( destPath ) ) {

...

}

Kommt es beim Anlegen in der Kette zu einer Ausnahme, wird nur die Ressource geschlossen, die geöffnet wurde. Wenn es also in dem gerade genannten Beispiel bei der ersten Initialisierung von in knallt, wird die Belegung von out erst gar nicht begonnen und daher auch nicht geschlossen. (Intern setzt der Compiler das als geschachtelte try-catch-finally-Blöcke um.)

 

Zum Seitenanfang

8.7.4    try mit Ressourcen auf null-Ressourcen Zur vorigen ÜberschriftZur nächsten Überschrift

Dass immer zum Abschluss eines try-mit-Ressourcen-Blocks ein close() aufgerufen wird, ist nicht ganz korrekt. Es gibt nur dann einen Schließversuch, wenn die Ressource ungleich null ist.

[zB]  Beispiel

Der Codebaustein compiliert und führt zu einer Konsolenausgabe:

try ( Scanner scanner1 = null; Scanner scanner2 = null ) {

System.out.println( "Ok" );

}

Bei Konstruktoren ist ein Objekt ja immer gegeben, aber es gibt auch Fabrikaufrufe, bei denen vielleicht null herauskommen kann. Für diese Fälle ist es ganz praktisch, dass try mit Ressourcen dann nichts macht, um eine NullPointerException beim close() zu vermeiden.

 

Zum Seitenanfang

8.7.5    Ausnahmen vom close() Zur vorigen ÜberschriftZur nächsten Überschrift

Unser Scanner-Programm aus dem ersten Beispiel hat eine Besonderheit, denn keine der Methoden löst eine geprüfte Ausnahme aus – weder getSystemResourceAsStream(…), new Scanner(InputStream), nextLine() noch das close(), das try mit Ressourcen automatisch aufruft. Anders ist es, wenn die Ressource ein klassischer Datenstrom (InputStream/OutputStream/Reader/Writer) ist, denn dort deklariert die close()-Methode eine IOException. Die muss daher auch behandelt werden, wie es das folgende Beispiel zeigt:

Listing 8.27    TryWithResourcesReadsLine, readFirstLine()

static String readFirstLine( String file ) {

try ( BufferedReader br = Files.newBufferedReader(

Paths.get( file ), StandardCharsets.ISO_8859_1 ) ) {

return br.readLine();

}

catch ( IOException e ) { e.printStackTrace(); return null; }

}

Wenn try mit Ressourcen verwendet wird, bleibt die deklarierte Ausnahme bei close() bestehen; es zaubert die in der Regel ausgelöste IOException nicht weg, und entweder muss ein fangendes catch her oder die Ausnahme muss weitergeleitet werden. Daraus ergibt sich ein interessanter Nebeneffekt: Hat ein Aufruf von einem IOException-auslösenden close() im Code gefehlt und wird Programmcode in der try-mit-Ressourcen-Syntax umgeschrieben, so führt der vom Compiler automatisch eingesetzte close()-Aufruf zu einem Compilerfehler, wenn die geprüfte IOException nicht behandelt wird.

[»]  Hinweis

Löst close() eine geprüfte Ausnahme aus und wird diese nicht behandelt, so kommt es zum Compilerfehler. Die close()-Methode vom BufferedReader löst zum Beispiel eine IOException aus, sodass sich die folgende Methode nicht übersetzen lässt:

void no() {

try ( Reader r = new BufferedReader(null) ) { } // inline image Compilerfehler

}

Der Ausdruck new BufferedReader(null) benötigt keine Behandlung, denn der Konstruktor löst keine Ausnahme aus. Einzig die nicht behandelte Ausnahme von close() führt zu »exception thrown from implicit call to close() on resource variable 'r'«.

 

Zum Seitenanfang

8.7.6    Unterdrückte Ausnahmen * Zur vorigen ÜberschriftZur nächsten Überschrift

Aufmerksame Leser haben bestimmt schon ein Detail wahrgenommen: In Tabelle 8.3 steht »vereinfachte ausgeschriebene Implementierung«, was vermuten lässt, dass es ganz so einfach doch nicht ist. Das stimmt, denn es können zwei Ausnahmen auftauchen, die einiges an Sonderbehandlung benötigen:

  • Ausnahme im try-Block, an sich unproblematisch

  • Ausnahme beim close(), auch an sich unproblematisch. Aber es gibt mehrere close()-Aufrufe, wenn nicht nur eine Ressource verwendet wurde: Ungünstig.

  • Die Steigerung: Ausnahme im try-Block und dann auch noch Ausnahme(n) beim close(). Das ist ein echtes Problem!

Eine Ausnahme allein ist kein Problem, aber zwei Ausnahmen auf einmal bilden ein großes Problem, da ein Programmblock nur genau eine Ausnahme melden kann und nicht eine Sequenz von Ausnahmen. Daher sind verschiedene Fragen zu klären, falls der try-Block und close() beide eine Ausnahme auslösen:

  • Welche Ausnahme ist wichtiger? Die Ausnahme im try-Block oder die vom close()?

  • Wenn es zu zwei Ausnahmen kommt: Soll die von close() vielleicht immer verdeckt werden und immer nur die vom try-Block zum Anwender kommen?

  • Wenn beide Ausnahmen gleich wichtig sind, wie sollen sie gemeldet werden?

Wie haben sich die Java-Ingenieure entschieden? Eine Ausnahme bei close() darf bei einem gleichzeitigen Auftreten einer Exception im try-Block auf keinen Fall verschwinden.[ 190 ](In einem frühen Prototyp war dies tatsächlich der Fall – die Ausnahme wurde komplett geschluckt. ) Wie also beide Ausnahmen melden? Hier gibt es einen Trick: Da die Ausnahme im try-Block wichtiger ist, ist sie die »Hauptausnahme«, und die close()-Ausnahme kommt Huckepack als Extra-Information mit obendrauf.

Dieses Verhalten soll das nächste Beispiel zeigen. Um die Ausnahmen besser steuern zu können, soll eine eigene AutoCloseable-Implementierung eine Ausnahme in close() auslösen.

Listing 8.28    src/main/java/com/tutego/insel/exception/NotCloseable.java, Ausschnitt

public class NotCloseable implements AutoCloseable {

@Override public void close() {

throw new UnsupportedOperationException( "close() mag ich nicht" ); // inline image

}

}

Die Klasse NotCloseable wollen wir als Ressource nutzen:

Listing 8.29    src/main/java/com/tutego/insel/exception/SuppressedClosed.java, Ausschnitt

public class SuppressedClosed {

public static void main( String[] args ) {

try ( NotCloseable res = new NotCloseable() ) {

throw new NullPointerException(); // inline image

}

}

}

NotCloseable löst im close() eine Ausnahme aus, die beim try-mit-Ressourcen ankommt. Ohne catch bricht die JVM den Thread ab und das Resultat auf der Konsole ist:

Exception in thread "main" java.lang.NullPointerException

at com.tutego.insel.exception.SuppressedClosed.main(SuppressedClosed.java:6)

Suppressed: java.lang.UnsupportedOperationException: close() mag ich nicht

at com.tutego.insel.exception.NotCloseable.close(NotCloseable.java:4)

at com.tutego.insel.exception.SuppressedClosed.main(SuppressedClosed.java:7)

Die Hauptausnahme ist die NullPointerException. Die interessante Zeile beginnt mit Suppressed:, denn dort ist die close()-Ausnahme referenziert. An den Aufrufer kommt die spannende Ausnahme des misslungenen try-Blocks aber nicht direkt von close(), sondern verpackt in der Hauptausnahme und muss extra erfragt werden.

Zum Vergleich: Kommentieren wir throw new NullPointerException() aus, gibt es nur noch die close()-Ausnahme, und es folgt auf der Konsole:

Exception in thread "main" java.lang.UnsupportedOperationException: close() mag ich nicht

at com.tutego.insel.exception.NotCloseable.close(NotCloseable.java:4)

at com.tutego.insel.exception.SuppressedClosed.main(SuppressedClosed.java:7)

Die Ausnahme ist also nicht irgendwo anders untergebracht, sondern die »Hauptausnahme«. Eine Steigerung ist, dass es mehr als eine Ausnahme beim Schließen geben kann. Simulieren wir auch dies wieder an einem Beispiel, indem wir unser Beispiel um eine Zeile ergänzen:

Listing 8.30    src/main/java/com/tutego/insel/exception/SuppressedClosed2.java, Ausschnitt

try ( NotCloseable res1 = new NotCloseable();

NotCloseable res2 = new NotCloseable() ) {

throw new NullPointerException();

}

Aufgerufen führt dies zu:

Exception in thread "main" java.lang.NullPointerException

at com.tutego.insel.exception.SuppressedClosed2.main(SuppressedClosed2.java:7)

Suppressed: java.lang.UnsupportedOperationException: close() mag ich nicht

at com.tutego.insel.exception.NotCloseable.close(NotCloseable.java:4)

at com.tutego.insel.exception.SuppressedClosed2.main(SuppressedClosed2.java:8)

Suppressed: java.lang.UnsupportedOperationException: close() mag ich nicht

at com.tutego.insel.exception.NotCloseable.close(NotCloseable.java:4)

at com.tutego.insel.exception.SuppressedClosed2.main(SuppressedClosed2.java:8)

Jede unterdrückte close()-Ausnahme taucht auf.

[»]  Umsetzung

In Abschnitt 8.4.5, »Abschlussbehandlung mit finally«, wurde das Verhalten vorgestellt, dass eine Ausnahme im finally eine Ausnahme im try-Block unterdrückt. Der Compiler setzt bei der Umsetzung vom try mit Ressourcen das close() in einen finally-Block. Ausnahmen im finally-Block sollen eine mögliche Hauptausnahme aber nicht schlucken. Daher fängt die Umsetzung vom Compiler jede mögliche Ausnahme im try-Block ab sowie die close()-Ausnahme und hängt diese Schließausnahme, falls vorhanden, an die Hauptausnahme.

Spezielle Methoden in Throwable *

Damit eine normale Exception die unterdrückten close()-Ausnahmen Huckepack nehmen kann, gibt es in der Basisklasse Throwable zwei besondere Methoden:

final class java.lang.Throwable
  • final Throwable[] getSuppressed()

    Liefert alle unterdrückten Ausnahmen. Die printStackTrace(…)-Methode zeigt alle unterdrückten Ausnahmen und greift auf getSuppressed() zurück. Für Anwender wird es selten Anwendungsfälle für diese Methode geben.

  • final void addSuppressed(Throwable exception)

    Fügt eine neue unterdrückte Ausnahme hinzu. In der Regel ruft der finally-Block vom try mit Ressourcen die Methode auf, doch wir können auch selbst die Methode nutzen, wenn wir mehr als eine Ausnahme melden wollen. Die Java-Bibliothek selbst nutzt das bisher nur an sehr wenigen Stellen.

Neben den beiden Methoden gibt es einen protected-Konstruktor, der bestimmt, ob es überhaupt unterdrückte Ausnahmen geben soll oder ob sie nicht vielleicht komplett geschluckt werden. Wenn, dann zeigt auch printStackTrace(…) sie nicht mehr an.

[»]  Blick über den Tellerrand

In C++ gibt es Destruktoren, die beliebige Anweisungen ausführen, wenn ein Objekt freigegeben wird. Hier lässt sich auch das Schließen von Ressourcen realisieren. C# nutzt statt try das spezielle Schlüsselwort using, mit Typen, die die Schnittstelle IDisposable implementieren, und zwar mit einer Methode Dispose() statt close() (in Java sollte die Schnittstelle ursprünglich auch Disposable statt nun AutoCloseable heißen). In Python 2.5 wurde ein context management protocol mit dem Schlüsselwort with realisiert, sodass Python automatisch beim Betreten eines Blocks __enter__() aufruft und beim Verlassen die Methode __exit__(). Das ist insofern interessant, als hier zwei Methoden zur Verfügung stehen. Bei Java ist es nur close() beim Verlassen des Blocks, aber es gibt keine Methode zum Betreten eines Blocks. So etwas muss beim Anlegen der Ressource erledigt werden.

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java ist auch eine Insel Java ist auch eine Insel

Jetzt Buch bestellen


 Buchempfehlungen
Zum Rheinwerk-Shop: Captain CiaoCiao erobert Java

Captain CiaoCiao erobert Java




Zum Rheinwerk-Shop: Java SE 9 Standard-Bibliothek

Java SE 9 Standard-Bibliothek




Zum Rheinwerk-Shop: Algorithmen in Java

Algorithmen in Java




Zum Rheinwerk-Shop: Objektorientierte Programmierung

Objektorientierte Programmierung




 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2021

Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.

Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de



Cookie-Einstellungen ändern