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.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