26.03.2004 Wiederholung: Ausnahmebehandlung Wdh.: Exceptions werfen und fangen • Problem in vielen Programmiersprachen • Deklarieren und Werfen von Exceptions • Fehler werden auf dem gleichen Weg zurückgegeben wie reguläre Rückgabewerte ¾ Programmierer versuchen, Fehlersignale in Randbereichen des fachlichen Wertebereichs unterzubringen • Bedeutung so codierter Fehlersignale muss informell vereinbart werden ¾ Gefahr: falsch interpretierte oder nicht behandelte Fehlercodes typ methode (...) throws Exceptionklasse1, Exceptionklasse2 { ... throw new Exceptionklasse1(); // oder throw new Exceptionklasse2(Nachricht); ... } • Fangen und Behandeln von Exceptions • Lösung: Exceptions • • • • ... try {...} catch (Exceptionklasse1 e) {...} catch (Exceptionklasse2 e) {...} finally {...} ... eigener Kanal für Signalisierung von Fehlern eigene Datenstrukturen für Fehlersignale formelle Deklaration möglicher Fehlersignale erzwungene Behandlung von Fehlersignalen Java-Einführungskurs 1 Java-Einführungskurs 2 Wiederholung: Behandlungsvarianten Wiederholung: Eigene Exceptions • Exception mit catch fangen und behandeln • Ableitung eigener Exceptions von Oberklasse Exception • Deklaration eines leeren Konstruktors und eines Konstruktors mit String-Parameter, um Exceptions beim Werfen erzeugen zu können • Blaupause für Implementierung eigener Exceptions: • Fehler dort behandeln, wo er signalisiert worden ist • Exception mit catch fangen und andere Exception werfen public class EigeneException extends Exception { public EigeneException() { super(); } public EigeneException(String message) { super(message); } } • z.B., um technische Fehlersignale in fachliche zu verwandeln und sie auf höherer Ebene behandeln zu lassen • Exception nicht fangen, sondern "weiterfliegen" lassen • Fehlersignal nicht selbst behandeln, sondern von höherer Ebene behandeln lassen • Erinnerungen • Bei der Ableitung werden Oberklassen-Konstruktoren nicht vererbt • Wenn wir einen parametrisierten Konstruktor deklarieren, erzeugt Java keinen impliziten leeren Konstruktor, wir müssen ihn darum selbst deklarieren Java-Einführungskurs 3 Wiederholung: JavaJava-Klassenbibliothek • • • • • • • • • • • java.applet java.awt java.beans java.io java.lang java.net java.rmi java.security java.sql java.util javax.swing 4 Wiederholung: Strings Applet-Programmierung GUI-Programmierung mit AWT JavaBeans™-Entwicklung Ein-/Ausgabe-Operationen, Datenströme fundamentale Klassen (z.B. String) Netzwerkfunktionen Remote Method Invocation Zertifikate, Kryptographie Datenbank-Funktionen Datenstrukturen GUI-Programmierung mit Swing • Referenztypen mit einigen Besonderheiten • direkte Zuweisung von Literalen: String s = "Hello"; • Konkatenation mit Operator: String t = s + "World"; • Methoden von Literalen aufrufbar: "HelloWorld".equals(t) • unveränderbar: Verknüpfungen/Methoden erzeugen neue Objekte • • • • verschiedene Konstruktoren zur String-Erzeugung Methoden für String- und Teilstring-Vergleiche Methoden zur String-Manipulation Typumwandlung von und zu Strings • String double • double String • und viele mehr (XML, CORBA, Namensdienste, Sound...) Java-Einführungskurs Java-Einführungskurs 5 Lehrstuhl für Angewandte Telematik/e-Business Java-Einführungskurs s d d s = = = = "2.71828"; Double.parseDouble(s); // 2.71828 3.14159; String.valueOf(d); // "3.14159" 6 1 26.03.2004 Ü4.1 Null Peilung Ü4.2 Ausnahmezustand Die Klasse java.lang.NullPointerException beschreibt den Versuch, auf eine Referenzvariable zuzugreifen, in der statt eines Objektes die Referenz null abgelegt ist. Welche Informationen können Sie ohne Kenntnis des genauen Programmcodes aus folgender Programmausgabe ziehen? • Das folgende Programm soll eine double-Fließkommazahl von der Tastatur einlesen, sie in einen String umwandeln und diesen wieder ausgeben. Falls die Umwandlung nicht möglich ist (weil der Benutzer etwas eingegeben hat, das sich nicht nach double umwandeln lässt, z.B. "schrott"), soll das Programm den Benutzer so lange zur Eingabe auffordern, bis er eine gültige double-Zahl eingibt. • In der main-Methode wird die Methode readDouble aufgerufen. Diese nimmt in der Anweisung s = in.readLine(); eine Tastatureingabe (d.h. einen String) entgegen und wandelt ihn in der Anweisung d = Double.parseDouble(s); in eine double-Zahl um. Um diese Anweisungen herum ist eine do-while-Schleife angedeutet, die dafür sorgen soll, dass die Eingabe so oft angefordert wird, bis die Typumwandlung erfolgreich war. java.lang.NullPointerException at Peilung.problem(Peilung.java:6) at Peilung.main(Peilung.java:10) • in Zeile 10 der Methode main von Peilung (gespeichert in Peilung.java) wurde die Methode problem aufgerufen • in Zeile 6 der Methode problem von Peilung wurde eine NullPointerException geworfen ¾ dort wurde versucht, auf ein Objekt zuzugreifen, obwohl in der betreffenden Variable null statt der Referenz stand Java-Einführungskurs • Die Fehlerbehandlung für den Fall, dass die Typumwandlung nicht erfolgreich war, soll von Ihnen in den folgenden Aufgabenteilen ausprogrammiert werden. 7 Java-Einführungskurs Ü4.2 Ausnahmezustand Ü4.2.1 "unreported "unreported exception" exception" import java.io.*; public class EingabeValidierung { // Eingabekanal von der Tastatur private static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 1. Beim Kompilierungsversuch erhalten wir die Meldung EingabeValidierung.java:17: unreported exception java.io.IOException; must be caught or declared to be thrown • Sie weist darauf hin, dass die Methode readLine (der Klasse BufferedReader) eine IOException werfen kann, die jedoch noch nirgends von uns gefangen wird. • Die Methode parseDouble der Klasse Double kann eine NumberFormatException werfen, die wir auch noch nicht abgefangen haben – darüber beschwert der Compiler sich jedoch nicht. • Welcher Unterschied zwischen java.io.IOException und java.lang.NumberFormatException ist für die Compiler-Fehlermeldung verantwortlich? public static double readDouble() { String s; double d = 0.0; boolean korrekt = true; } } // String-Eingabe und Typumwandlung - zu vervollständigen: do { System.out.print("Bitte double-Zahl eingeben: "); s = in.readLine(); // Tastatureingabe entgegennehmen d = Double.parseDouble(s); // Eingabestring in double wandeln } while (!korrekt); return d; public static void main (String[] args) { double eingabe = readDouble(); System.out.println("Eingabe: " + eingabe); } Java-Einführungskurs 9 Java-Einführungskurs Ü4.2.1 "unreported "unreported exception" exception" Ü4.2.2 trytry-catchcatch-Struktur • Oberklassen von IOException 2. Ergänzen Sie den Inhalt der do-while-Schleife um eine try-catch-Struktur, die beide Arten von Exceptions abfängt. java.lang.Object java.lang.Throwable java.lang.Exception java.io.IOException java.lang.Object java.lang.Throwable java.lang.Exception java.lang.RuntimeException java.lang.IllegalArgumentException java.lang.NumberFormatException • RuntimeExceptions sind "unchecked" können prinzipiell überall auftreten nicht sinnvoll, überall zu prüfen, ob sie abgefangen werden Compiler erzwingt Behandlung nicht i.d.R. Weitergabe an die JVM Java-Einführungskurs 10 ... do { System.out.print("Bitte double-Zahl eingeben: "); try { korrekt = true; s = in.readLine(); d = Double.parseDouble(s); } catch (IOException e) { // nur vorerst leer } catch (NumberFormatException e) { System.out.println("Keine zulaessige double-Zahl!"); korrekt = false; } } while (!korrekt); ... • Oberklassen von NumberFormatException • • ¾ ¾ 8 11 Lehrstuhl für Angewandte Telematik/e-Business Java-Einführungskurs 12 2 26.03.2004 Ü4.2.3 Reihenfolge der catchcatch-Blöcke Ü4.2.4 leere catchcatch-Blöcke 3. Ist die Reihenfolge der catch-Blöcke in diesem Beispiel von Bedeutung? Warum? 4. Obwohl die IOException in unserem Beispiel kaum auftreten kann, ist ein leerer catch-Block extrem schlechter Programmierstil. Warum? catch (IOException e) { // nur vorerst leer } catch (NumberFormatException e) { System.out.println("Keine zulaessige double-Zahl!"); korrekt = false; } Reihenfolge ist nicht von Bedeutung, da IOException und NumberFormatException keine Vererbungsbeziehung haben. Keiner der beiden catch-Blöcke kann also Exceptions fangen, die für den anderen bestimmt sind. Java-Einführungskurs 13 catch (IOException e) { // nur vorerst leer } catch (NumberFormatException e) { System.out.println("Keine zulaessige double-Zahl!"); korrekt = false; } ... Die Exception wird zwar gefangen, aber in keiner Weise verarbeitet – aus dem leeren catch-Block wird direkt zum regulären Programmcode weitergesprungen. "Verschlucken" von Exceptions ist aber kaum sinnvoll, da der Fehler damit ignoriert wird. Java-Einführungskurs Ü4.2.5 ExceptionException-Behandlung Ü4.2.6 ExceptionException-Klassendeklaration 5. Welche drei Möglichkeiten haben wir, auf die IOException in diesem Beispiel (bzw. im Allgemeinen auf jede Exception) zu reagieren? 6. Erweitern Sie die Methode readDouble so, dass sie im Fall einer IOException eine neue, von Ihnen deklarierte InputException wirft. Deklarieren Sie dazu InputException als Unterklasse von Exception. • Exception mit catch fangen und behandeln • Fehler dort behandeln, wo er signalisiert worden ist public class InputException extends Exception { public InputException() { super(); } • Exception mit catch fangen und andere Exception werfen • z.B., um technische Fehlersignale in fachliche zu verwandeln und sie auf höherer Ebene behandeln zu lassen public InputException(String message) { super(message); • Exception nicht fangen (kein catch), sondern "weiterfliegen" lassen } } • Fehlersignal nicht selbst behandeln, sondern von höherer Ebene behandeln lassen Java-Einführungskurs 15 Ü4.2.6 Werfen einer eigenen Exception } Java-Einführungskurs 16 Ü4.2.7 Behandeln eigener Exceptions public static double readDouble() throws InputException { String s; double d = 0.0; boolean korrekt = true; do { System.out.print("Bitte double-Zahl eingeben: "); try { korrekt = true; s = in.readLine(); d = Double.parseDouble(s); } catch (IOException e) { throw new InputException("Fehler in Tastatureingabe"); } catch (NumberFormatException e) { System.out.println("Keine zulaessige double-Zahl!"); korrekt = false; } } while (!korrekt); return d; Java-Einführungskurs 14 17 Lehrstuhl für Angewandte Telematik/e-Business 7. Der Compiler weist darauf hin, dass die von readDouble geworfene InputException in main noch nicht behandelt wird. Überlegen Sie, welche beiden Möglichkeiten Sie dafür haben, und implementieren Sie eine von beiden in main. • Alternative 1: Fangen und behandeln public static void main (String[] args) { try { double eingabe = readDouble(); System.out.println("Eingabe: " + eingabe); } catch (InputException e) { System.out.println (e.getMessage()); } } Bitte double-Zahl eingeben: Fehler in Tastatureingabe Java-Einführungskurs 18 3 26.03.2004 Ü4.2.7 Behandeln eigener Exceptions Ü4.3 StringString-Vergleiche • Alternative 2: "Weiterfliegen" lassen (d.h. zum aufrufenden Programmteil durchreichen) String s1 = "Test"; String s2 = s1; String s3 = "Te"; String s4 = "st"; String s5 = s3 + s4; Welchen Wert haben die folgenden Ausdrücke? public static void main (String[] args) throws InputException { double eingabe = readDouble(); System.out.println("Eingabe: " + eingabe); } Da dies die main-Methode ist, ist der aufrufende Programmteil die JVM, wo die Exception einfach ausgegeben wird: s1 == s2 s1.equals(s2) s1.compareTo(s2) true: gleiche Referenz true: gleiche Referenz Æ gleiche Zeichenketten 0: gleiche Referenz Æ gleiche Zeichenketten s3 == s4 s3.equals(s4) s3.compareTo(s4) false: verschiedene Referenzen false: verschiedene Zeichenketten -31: 'T' liegt in ASCII 31 Zeichen vor 's' s1 == s5 s1.equals(s5) s1.compareTo(s5) false: verschiedene Referenzen true: gleiche Zeichenketten 0: gleiche Zeichenketten ('T': ASCII 84; 's': ASCII 115) Bitte double-Zahl eingeben: Exception in thread "main" InputException: Fehler in Tastatureingabe at EingabeValidierung.readDouble(EingabeValidierung.java:19) at EingabeValidierung.main(EingabeValidierung.java:33) Java-Einführungskurs 19 Java-Einführungskurs 20 Ü4.4 Referenzen in main Ü4.4 StringString-Parameter public static void main(String[] args) { String sAussen = "Hello"; String tAussen = "klein"; methode(sAussen, tAussen); System.out.println(sAussen); System.out.println(tAussen); } public class StringTest { public static void methode(String sInnen, String tInnen) { sInnen = "World"; tInnen.toUpperCase(); System.out.println(sInnen); System.out.println(tInnen); } public static void main(String[] args) { String sAussen = "Hello"; String tAussen = "klein"; methode(sAussen, tAussen); System.out.println(sAussen); System.out.println(tAussen); } } main sAussen "Hello" tAussen "klein" Überlegen Sie, welche Ausgabe das Programm erzeugt, und prüfen Sie dann Ihre Vorhersage. Wie ist das Verhalten zu erklären? Java-Einführungskurs 21 Java-Einführungskurs 22 Ü4.4 Referenzen in methode Ü4.4 Referenzen nach Rückkehr public static void methode(String sInnen, String tInnen) { sInnen = "World"; tInnen.toUpperCase(); System.out.println(sInnen); System.out.println(tInnen); } public static void main(String[] args) { String sAussen = "Hello"; String tAussen = "klein"; methode(sAussen, tAussen); System.out.println(sAussen); System.out.println(tAussen); } main sAussen main "Hello" tAussen "klein" sAussen methode sInnen sInnen "Hello" tAussen "klein" methode tInnen "World" tInnen sInnen "KLEIN" World klein sInnen tInnen "World" tInnen main sAussen "KLEIN" World klein tAussen Hello klein Java-Einführungskurs 23 Lehrstuhl für Angewandte Telematik/e-Business Java-Einführungskurs 24 4 26.03.2004 Ü4.4 Begründung Pause public class StringTest { public static void methode(String sInnen, String tInnen) { sInnen = "World"; tInnen.toUpperCase(); // neues "KLEIN" nicht gespeichert System.out.println(sInnen); // "World" System.out.println(tInnen); // "klein" } public static void main(String[] args) { String sAussen = "Hello"; String tAussen = "klein"; methode(sAussen, tAussen); System.out.println(sAussen); // "Hello" System.out.println(tAussen); // "klein" } } „Take a break... ¨ • Merke: Methoden, Zuweisungen und Konkatenationen ändern nicht den Inhalt des betroffenen String-Objekts, sondern geben ein neues String-Objekt zurück! Java-Einführungskurs ...have a steaming cup of Java!“ 25 Lehrstuhl für Angewandte Telematik/e-Business Java-Einführungskurs 26 5