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

Pfeil 8 Ausnahmen müssen sein
Pfeil 8.1 Problembereiche einzäunen
Pfeil 8.1.1 Exceptions in Java mit try und catch
Pfeil 8.1.2 Geprüfte und ungeprüfte Ausnahmen
Pfeil 8.2 Geprüfte Ausnahmen
Pfeil 8.2.1 Letzte ausgeführte Java-Programme loggen
Pfeil 8.2.2 try-catch-Behandlung
Pfeil 8.2.3 throws im Methodenkopf angeben
Pfeil 8.3 Ungeprüfte Ausnahmen (RuntimeException)
Pfeil 8.3.1 Eine NumberFormatException fliegt
Pfeil 8.3.2 Bekannte RuntimeException-Klassen
Pfeil 8.3.3 Kann man abfangen, muss man aber nicht
Pfeil 8.4 Gut gefangen
Pfeil 8.4.1 Bitte nicht schlucken – leere catch-Blöcke
Pfeil 8.4.2 Wiederholung abgebrochener Bereiche *
Pfeil 8.4.3 Mehrere Ausnahmen auffangen
Pfeil 8.4.4 Ablauf einer Ausnahmesituation
Pfeil 8.4.5 Abschlussbehandlung mit finally
Pfeil 8.5 Die Klassenhierarchie der Ausnahmen
Pfeil 8.5.1 Eigenschaften des Exception-Objekts
Pfeil 8.5.2 Basistyp Throwable
Pfeil 8.5.3 Die Exception-Hierarchie
Pfeil 8.5.4 Oberausnahmen auffangen
Pfeil 8.5.5 Schon gefangen?
Pfeil 8.5.6 Alles geht als Exception durch
Pfeil 8.5.7 Zusammenfassen gleicher catch-Blöcke mit dem multi-catch
Pfeil 8.6 Auslösen eigener Exceptions
Pfeil 8.6.1 Mit throw Ausnahmen auslösen
Pfeil 8.6.2 Vorhandene Runtime-Ausnahmetypen kennen und nutzen
Pfeil 8.6.3 Parameter testen und gute Fehlermeldungen
Pfeil 8.6.4 Neue Exception-Klassen deklarieren
Pfeil 8.6.5 Eigene Ausnahmen als Unterklassen von Exception oder RuntimeException?
Pfeil 8.6.6 Ausnahmen abfangen und weiterleiten *
Pfeil 8.6.7 Aufruf-Stack von Ausnahmen verändern *
Pfeil 8.6.8 Präzises rethrow *
Pfeil 8.6.9 Geschachtelte Ausnahmen *
Pfeil 8.7 Automatisches Ressourcen-Management (try mit Ressourcen)
Pfeil 8.7.1 try mit Ressourcen
Pfeil 8.7.2 Die Schnittstelle AutoCloseable
Pfeil 8.7.3 Mehrere Ressourcen nutzen
Pfeil 8.7.4 try mit Ressourcen auf null-Ressourcen
Pfeil 8.7.5 Ausnahmen vom close()
Pfeil 8.7.6 Unterdrückte Ausnahmen *
Pfeil 8.8 Besonderheiten bei der Ausnahmebehandlung *
Pfeil 8.8.1 Rückgabewerte bei ausgelösten Ausnahmen
Pfeil 8.8.2 Ausnahmen und Rückgaben verschwinden – das Duo return und finally
Pfeil 8.8.3 throws bei überschriebenen Methoden
Pfeil 8.8.4 Nicht erreichbare catch-Klauseln
Pfeil 8.9 Harte Fehler – Error *
Pfeil 8.10 Assertions *
Pfeil 8.10.1 Assertions in eigenen Programmen nutzen
Pfeil 8.10.2 Assertions aktivieren und Laufzeit-Errors
Pfeil 8.10.3 Assertions feiner aktivieren oder deaktivieren
Pfeil 8.11 Zum Weiterlesen
 

Zum Seitenanfang

8.5    Die Klassenhierarchie der Ausnahmen Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Ausnahme ist ein Objekt vom Typ einer Klasse. Die Exception-Klassen selbst sind von anderen Ausnahmeklassen abgeleitet.

 

Zum Seitenanfang

8.5.1    Eigenschaften des Exception-Objekts Zur vorigen ÜberschriftZur nächsten Überschrift

Das Exception-Objekt, das uns in der catch-Klausel übergeben wird, ist reich an Informationen. So lässt sich erfragen, um welche Ausnahme es sich eigentlich handelt und wie die Fehlernachricht heißt. Auch der Stack-Trace lässt sich erfragen und ausgeben:

Listing 8.11    src/main/java/com/tutego/insel/exception/NumberFormatExceptionElements.java, main()

try {

Integer.parseInt( "19%" );

}

catch ( NumberFormatException e ) {

String name = e.getClass().getName();

String msg = e.getMessage();

String s = e.toString();



System.out.println( name );// java.lang.NumberFormatException

System.out.println( msg ); // For input string: "19%"

System.out.println( s ); // java.lang.NumberFormatException: For input string: "19%"



e.printStackTrace();

}

Im letzten Fall, mit e.printStackTrace(), bekommen wir auf dem Fehlerkanal System.err das Gleiche ausgegeben, was uns die virtuelle Maschine ausgibt, wenn wir die Ausnahme nicht abfangen:

java.lang.NumberFormatException

For input string: "19%"

java.lang.NumberFormatException: For input string: "19%"

java.lang.NumberFormatException: For input string: "19%"

at java.base/java.lang.NumberFormatException.forInputString(

NumberFormatException.java:65)

at java.base/java.lang.Integer.parseInt(Integer.java:652)

at java.base/java.lang.Integer.parseInt(Integer.java:770)

at c.t.i.e.NumberFormatExceptionElements.main(NumberFormatExceptionElements.java:7)

Die Ausgabe besteht aus dem Klassennamen der Exception, der Meldung und dem Stack-Trace. printStackTrace(…) ist parametrisiert und kann auch in einen Ausgabekanal geschickt werden.

 

Zum Seitenanfang

8.5.2    Basistyp Throwable Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Exception ist ein Objekt, dessen Typ direkt oder indirekt von java.lang.Throwable abgeleitet ist. (Die Namensgebung mit -able legt eine Schnittstelle nahe, aber Throwable ist eine nichtabstrakte Klasse.)

Von dort aus verzweigt sich die Hierarchie der Ausnahmearten nach java.lang.Exception und java.lang.Error. Die Klassen, die aus Error hervorgehen, sollen hier nicht weiterverfolgt werden. Es handelt sich bei ihnen um so schwerwiegende Ausnahmen, dass sie zur Beendigung des Programms führen und vom Programmierer nicht weiter beachtet werden müssen und sollten. Throwable vererbt eine Reihe von nützlichen Methoden, die in Abbildung 8.8 zu sehen sind. Sie fasst gleichzeitig die Vererbungsbeziehungen noch einmal zusammen.

UML-Diagramm der wichtigen Oberklasse »Throwable«

Abbildung 8.8    UML-Diagramm der wichtigen Oberklasse »Throwable«

 

Zum Seitenanfang

8.5.3    Die Exception-Hierarchie Zur vorigen ÜberschriftZur nächsten Überschrift

Jede Benutzerausnahme wird von java.lang.Exception abgeleitet. Die Exceptions sind Fehler oder Ausnahmesituationen, die vom Programmierer behandelt werden sollten. Die Klasse Exception teilt sich dann nochmals in weitere Unterklassen bzw. Unterhierarchien auf. Abbildung 8.9 zeigt einige Unterklassen der Klasse Exception.

Ausgewählte Unterklassen von Exception

Abbildung 8.9    Ausgewählte Unterklassen von Exception

 

Zum Seitenanfang

8.5.4    Oberausnahmen auffangen Zur vorigen ÜberschriftZur nächsten Überschrift

Eine Konsequenz der Hierarchien besteht darin, dass es ausreicht, eine Ausnahme der Oberklasse aufzufangen. Wenn zum Beispiel eine FileNotFoundException auftritt, ist diese Klasse von IOException abgeleitet, was bedeutet, dass FileNotFoundException eine Spezialisierung darstellt. Wenn wir jede IOException auffangen, behandeln wir damit auch gleichzeitig die FileNotFoundException mit (siehe Abbildung 8.10).

Erinnern wir uns noch einmal an das Dateibeispiel in Listing 8.9, das eine FileNotFoundException und eine IOException einzeln behandelt. Ist die Behandlung aber die gleiche, lässt sie sich wie folgt zusammenfassen:

Listing 8.12    src/main/java/com/tutego/insel/exception/ReadGifSizeShort.java, main()

RandomAccessFile f = null;



try {

f = new RandomAccessFile( "duke.gif", "r" );

f.seek( 6 );



System.out.printf( "%s x %s Pixel%n", f.read() + f.read() * 256,

f.read() + f.read() * 256 );

}

catch ( IOException e ) {

System.err.println( "Allgemeiner Ein-/Ausgabefehler!" );

}

finally {

if ( f != null ) try { f.close(); } catch ( IOException e ) { }

}
»IOException« im Klassendiagramm

Abbildung 8.10    »IOException« im Klassendiagramm

Ausnahmen, die unterschiedlich behandelt werden müssen, verdienen immer getrennte catch-Klauseln. Das trifft z. B. auf FileNotFoundException und IOException zu, die wir in Listing 8.9 auch schon getrennt behandelt haben, was wohl auch besser so ist.

Auch wenn die Ausnahme über eine Oberklasse wie IOException aufgefangen wird, lässt sich die Ausnahme prinzipiell später wieder mit instanceof identifizieren. Wir könnten schreiben:

catch ( IOException e ) {

if ( e instanceof FileNotFoundException )

System.err.println( "Datei ist nicht vorhanden!" );

else

System.err.println( "Allgemeiner Ein-/Ausgabefehler!" );

}

Aus Gründen der Übersichtlichkeit sollte diese Technik jedoch sparsam angewendet werden.

 

Zum Seitenanfang

8.5.5    Schon gefangen? Zur vorigen ÜberschriftZur nächsten Überschrift

Der Java-Compiler prüft, ob Ausnahmen vielleicht schon in der Kette aufgefangen wurden, und meldet einen Fehler, wenn catch-Blöcke nicht erreichbar sind. Wir haben gesehen, dass FileNotFoundException eine spezielle IOException ist und ein catch(IOException e) Ausnahmen vom Typ FileNotFoundException gleich mit fängt.

try {

...

}

catch ( IOException e ) { // fange IOException und alle Unterklassen auf

...

}

Natürlich kann eine FileNotFoundException weiterhin als eigener Typ aufgefangen werden, allerdings ist es wichtig, die Reihenfolge der catch-Blöcke zu beachten. Denn die Reihenfolge ist absolut relevant; die Typtests beginnen oben und laufen dann weiter nach unten durch. Wenn ein früher catch schon Ausnahmen eines gewissen Typs abfängt, also etwa ein catch auf IOException alle Ein-/Ausgabefehler, so ist ein nachfolgender catch auf die FileNotFoundException falsch.

Nehmen wir an, ein try-Block kann eine FileNotFoundException und eine IOException auslösen. Dann ist die linke Behandlung aus Tabelle 8.2 korrekt, aber die rechte falsch:

Richtig

Mit Compilerfehler

try {

...

}

catch ( FileNotFoundException e ) {

}

catch ( IOException e ) {

}
try {

...

}

catch ( IOException e ) {

}

catch ( FileNotFoundException e ) { // inline image

}

Tabelle 8.2    Die Reihenfolge der »catch«-Blöcke spielt eine Rolle.

 

Zum Seitenanfang

8.5.6    Alles geht als Exception durch Zur vorigen ÜberschriftZur nächsten Überschrift

Löst ein Programmblock etwa eine IOException, MalformedURLException und eine FileNotFoundException aus, und sollen die drei Ausnahmen gleich behandelt werden, so fängt ein catch (IOException e) die beiden Typen FileNotFoundException und MalformedURLException gleich mit ab, da beide Unterklassen von IOException sind. So behandelt ein Block alle drei Ausnahmetypen. Das ist praktisch.

Nun gibt es jedoch auch Ausnahmen, die in der Vererbungsbeziehung nebeneinanderliegen, etwa SQLException und IOException. Was ist, wenn die Ausnahmebehandlung gleich sein soll? Die naheliegende Idee ist, in der Ausnahmehierarchie so weit nach oben zu laufen, bis eine gemeinsame Oberklasse gefunden wurde. Bei SQLException und IOException ist das Exception – sozusagen der kleinste gemeinsame Nenner. Also könnten Entwickler auf die Idee kommen, Exception aufzufangen und dort einmal die Ausnahme zu behandeln. Anstatt also einen Behandler zweimal zu schreiben und eine Codeduplizierung zu verursachen wie in

try {

irgendwas kann SQLException auslösen ...

irgendwas kann IOException auslösen ...

}

catch ( SQLException e ) { Behandlung }

catch ( IOException e ) { Behandlung }

lässt sich aufgrund der identischen Ausnahmebehandlungen eine Optimierung versuchen, die etwa so aussieht:

try {

irgendwas kann SQLException auslösen ...

irgendwas kann IOException auslösen ...

}

catch ( Exception e ) { Behandlung }

Von dieser Lösung ist dringend abzuraten! Denn was für andere Ausnahmetypen gut funktionieren mag, ist für catch(Exception e) gefährlich, weil wirklich jede Ausnahme aufgefangen und in der Ausnahmebehandlung bearbeitet wird. Taucht beispielsweise eine null-Referenz durch eine nicht initialisierte Variable mit Referenztyp auf, so würde dies fälschlicherweise ebenso behandelt; der Programmfehler hat aber nichts mit der SQLException oder IOException zu tun:

try {

Point p = null;

p.x = 2; // inline image NullPointerException

int i = 0;

int x = 12 / i; // inline image Ganzzahlige Division durch 0



irgendwas kann SQLException auslösen ...

irgendwas kann IOException auslösen ...

}

catch ( Exception e ) { Behandlung }

Eine NullPointerException und die ArithmeticException sollen nicht mitbehandelt werden. Das zentrale Problem ist hier, dass diese Ausnahmen ungeprüfte Ausnahmen vom Typ RuntimeException sind und RuntimeException eine Unterklasse von Exception ist. Fangen wir alle Exception-Typen, so wird alles mitgefangen – und RuntimeException eben auch. Es ist nicht möglich, alle Nicht-Laufzeitausnahmen abzufangen, was etwa funktionieren würde, wenn RuntimeException keine Unterklasse von Exception wäre, etwa ein Throwable – aber das haben die Sprachdesigner nicht so modelliert.

Wir werden gleich sehen, wie sich das Problem elegant lösen lässt.

Wenn main(String[]) alles weiterleitet

Ist die Ausnahmebehandlung in einem Hauptprogramm ganz egal, so können wir alle Ausnahmen auch an die Laufzeitumgebung weiterleiten, die dann das Programm – genau genommen den Thread – im Fehlerfall abbricht:

Listing 8.13    src/main/java/com/tutego/insel/exception/IDontCare.java, main()

public static void main( String[] args ) throws Exception {

Scanner in = new Scanner( Paths.get( "lyrics.txt" ) );

System.out.println( in.nextLine() );

}

Das funktioniert, da alle Ausnahmen von der Klasse Exception[ 182 ](Genauer gesagt, sind alle Ausnahmen in Java von der Exception-Oberklasse Throwable abgeleitet. ) abgeleitet sind. Wird die Ausnahme nirgendwo sonst aufgefangen, erfolgt die Ausgabe einer Laufzeitfehlermeldung, denn das Exception-Objekt ist beim Interpreter, also bei der virtuellen Maschine, auf der äußersten Aufrufebene gelandet. Natürlich ist das kein guter Stil (obwohl es auch in diesem Buch so gemacht wird, um Programme kurz zu halten), denn Ausnahmen sollten in jedem Fall behandelt werden.

 

Zum Seitenanfang

8.5.7    Zusammenfassen gleicher catch-Blöcke mit dem multi-catch Zur vorigen ÜberschriftZur nächsten Überschrift

Greift ein Programm auf Teile zurück, die scheitern können, so ergeben sich in komplexeren Abläufen schnell Situationen, in denen unterschiedliche Ausnahmen auftreten können. Entwickler sollten versuchen, den Programmcode in einem try-Block durchzuschreiben und dann in catch-Blöcken auf alle möglichen Ausnahmen zu reagieren, die den Block vom korrekten Durchlaufen abgehalten haben.

Oftmals kommt es zu dem Phänomen, dass die aufgerufenen Programmteile unterschiedliche Ausnahmetypen auslösen, aber die Behandlung der Ausnahmen gleich aussieht. Um Quellcode-Duplizierung zu vermeiden, sollte der Programmcode zusammengefasst werden. Nehmen wir an, die Behandlung der Ausnahmen SQLException und IOException soll gleich sein. Das mit einem catch(Exception e) zu lösen, ist keine gute Idee und sollte nie im Programmcode vorkommen, denn dann würden auch andere Ausnahmen mitgefangen, die mit der eigentlichen Ausnahme nichts zu tun hatten. Zum Glück gibt es eine elegante Lösung.

multi-catch

Eine spezielle Schreibweise für catch-Klauseln erlaubt es, mehrere Ausnahmen auf einmal aufzufangen. Diese Schreibweise heißt multi-catch. In der abgewandelten Variante von catch steht dann nicht mehr nur eine Ausnahme, sondern eine Sammlung von Ausnahmen, die ein | trennt. Der senkrechte Strich ist schon als Oder-Operator bekannt und wurde daher auch hier eingesetzt, denn die Ausnahmen sind ja auch als eine Oder-Verknüpfung zu verstehen. Die allgemeine Syntax ist:

try {

...

}

catch ( E1 | E2 | ... | En exception ) { ... }

Die Variable exception ist implizit final.

Um das multi-catch zu demonstrieren, nehmen wir ein Programm an, das eine Farbtabelle einliest. Die Datei besteht aus mehreren Zeilen, wobei in jeder Zeile die erste Zahl einen Index repräsentiert und die zweite Zahl den hexadezimalen RGB-Farbwert.

Listing 8.14    basiscolors.txt

0 000000

1 ff0000

8 00ff00

9 ffff00

Eine eigene Methode readColorTable(String) soll die Datei einlesen und ein int-Array der Größe 256 als Rückgabe liefern, wobei an den in der Datei angegebenen Positionen jeweils die Farbwerte eingetragen sind. Nicht belegte Positionen bleiben 0. Gibt es einen Ladefehler, soll die Rückgabe null sein und die Methode eine Meldung auf dem Fehlerausgabekanal ausgeben.

Das Einlesen soll die Scanner-Klasse übernehmen. Bei der Verarbeitung der Daten und der Füllung des Arrays sind diverse Ausnahmen möglich:

  • IOException: Die Datei ist nicht vorhanden, oder während des Einlesens kommt es zu Problemen.

  • InputMismatchException: Der Index oder die Hexadezimalzahl sind keine Zahlen (einmal zur Basis 10 und dann zur Basis 16). Die Ausnahme kommt vom Scanner.

  • ArrayIndexOutOfBoundsException: Der Index liegt nicht im Bereich von 0 bis 255.

Während die erste Ausnahme beim Dateisystem zu suchen ist, sind die zwei unteren Ausnahmen – unabhängig davon, dass sie ungeprüfte Ausnahmen sind – auf ein fehlerhaftes Format zurückzuführen. Die Behandlung soll immer gleich aussehen und kann daher gut in einem multi-catch zusammengefasst werden. Daraus folgt:

Listing 8.15    src/main/java/com/tutego/insel/exception/ReadColorTable.java, ReadColorTable

public class ReadColorTable {



private static int[] readColorTable( String filename ) {

Scanner input = null;

int[] colors = new int[ 256 ];

try {

input = new Scanner( Paths.get( filename ),

StandardCharsets.ISO_8859_1.name() );

while ( input.hasNextLine() ) {

int index = input.nextInt();

int rgb = input.nextInt( 16 );

colors[ index ] = rgb;

}

return colors;

}

catch ( IOException e ) {

System.err.printf( "Dateioperationen fehlgeschlagen%n%s%n", e );

}

catch ( InputMismatchException | ArrayIndexOutOfBoundsException e ) {

System.err.printf( "Datenformat falsch%n%s%n", e );

}

finally {

if ( input != null ) input.close();

}

return null;

}



public static void main( String[] args ) {

readColorTable( "basiscolors.txt" );

}

}

Der Bytecode sieht genauso aus wie mehrere gesetzte catch-Blöcke, also wie:

catch ( InputMismatchException e ) {

System.err.printf( "Datenformat falsch%n%s%n", e );

}

catch ( ArrayIndexOutOfBoundsException e ) {

System.err.printf( "Datenformat falsch%n%s%n", e );

}

Multi-catch-Blöcke sind also nur eine Abkürzung, daher teilen sie auch die Eigenschaften der normalen catch-Blöcke. Der Compiler führt die gleichen Prüfungen wie bisher durch, also ob etwa die genannten Ausnahmen im try-Block überhaupt ausgelöst werden können. Nur das, was in der durch | getrennten Liste aufgezählt ist, wird behandelt; unser Programm fängt zum Beispiel nicht generisch alle RuntimeExceptions ab. Und genauso dürfen die in catch oder multi-catch genannten Ausnahmen nicht in einem anderen (multi-)catch auftauchen.

Neben den Standardtests kommen neue Überprüfungen hinzu, ob etwa die exakt gleiche Exception zweimal in der Liste ist oder ob es Widersprüche durch Mengenbeziehungen gibt.

[»]  Hinweis

Der folgende multi-catch ist falsch:

try {

new RandomAccessFile( "", "" );

}

catch ( FileNotFoundException | IOException | Exception e ) { }

Der javac-Compiler meldet einen Fehler der Art »Alternatives in a multi-catch statement cannot be related by subclassing« und bricht ab.

Mengenprüfungen führt der Compiler auch ohne multi-catch durch, und Folgendes ist ebenfalls falsch:

try { new RandomAccessFile( "", "" ); }

catch ( Exception e ) { }

catch ( IOException e ) { }

catch ( FileNotFoundException e ) { }

Während allerdings eine Umsortierung der Zeilen die Fehler korrigiert – wie in Abschnitt 8.5.5, »Schon gefangen?«, erwähnt –, spielt die Reihenfolge bei multi-catch keine Rolle.

 


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