Exception Handling
- Einstieg
- Erster Kontakt
- Eine
Exception
behandeln - Mehrere
Exception
behandeln - Aufräumarbeiten -
finally
Stand: 6. Juni 2011
Einstieg
Exceptions (Ausnahmen) betreffen Methoden und Funktionen gleichermaßen. Der Einfachheit wird im Folgenden nur von Methoden gesprochen.
Im Normalfall erwarten wir, dass eine Methode einen bestimmten Wert berechnet/bestimmt oder gewünschte Seiteneffekte ausführt. Jedoch ist eine Methode nicht immer in der Lage die gewünschte Funktionalität wie erwartet zu liefern.
Ein Beispiel ist, wenn eine Methode die Daten einer bestimmten Datei auswerten soll, wobei die angegebene Datei nicht existiert. Oder es soll eine Berechnung für einen Parameter durchgeführt werden, wobei der Parameter außerhalb des zulässigen Wertebereichs liegt.
Nun könnte die entsprechende Methode das laufende Programm einfach beenden, was wir eigentlich nicht wollen. Eine weitere Möglichkeit wäre es, die Methode einen codierten Wert zurückgeben zu lassen. Das würde aber in der Aufrufhirachie zu erheblichen Problemen in der Programmierung führen.
Anstatt die Methode mit einem Rückgabewert zu beenden oder bis zum Ende
arbeiten zu lassen kommen hier die Exceptions (Ausnahmen) ins Spiel.
Die entsprechende Methode wird nicht wie erwartet bis zum Ende ausgeführt
und es wird auch kein Rückgabewert zurückgegeben,
sondern es wird eine Exception
geworfen.
Wirft eine Methode eine Exception
, gibt es für die aufrufende Methode
zwei Möglichkeiten. Die Methode kann die Exception
geeignet
behandeln oder an die ihrerseits aufrufende Methode weiterreichen.
Gibt es keine weitere aufrufende Methode, wird das Programm abgebrochen (zumindest bei
Single-Thread Anwendungen).
Ein wesentlicher Unterschied zu Java ist, dass keine Exceptions explizit weitergeleitet
werden muss. Wird eine Exception nicht behandelt, wird Sie automatisch an die aufrufende
Methode weitergereicht. In Scala verhalten sich alle Exceptions wie eine
RuntimeException
in Java. Aus diesem Grund gibt es auch keine throws
Deklaration für Methoden in Scala.
Erster Kontakt
Für einen ersten Kontakt mit Exceptions in Scala erstellen Sie eine Scala Klasse mit folgendem Inhalt. Stellen Sie zudem sicher, dass es keine Datei mit dem Namen "c:\test.txt" existiert, bzw. wählen Sie einen Dateinamen einer nicht existierenden Datei.
import java.io._ object FirstException{ def main(args: Array[String]){ println("Start") val is = new FileInputStream("c:\\test.txt") println("End") } }
Kompilieren Sie nun die Scala Datei. Wir stellen fest, dass die Kompilierung ohne Fehlermeldungen durchläuft, da in Scala keine Exception explizit verarbeitet bzw. weitergereicht werden muss.
Wenn Sie nun die kompilierte Scala Klasse ausführen, erhalten Sie die
geworfene java.io.FileNotFoundException
als Fehlerausgabe.
Die Ausgabe auf der Systemausgabe lautet in etwa:
Start Exception in thread "main" java.io.FileNotFoundException: c:\test.txt (Das System kann die angegebene Datei nicht finden) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.(FileInputStream.java:106) at java.io.FileInputStream.(FileInputStream.java:66) at firstException.FirstException$.main(FirstException.scala:8) at firstException.FirstException.main(FirstException.scala) ...
Eine Exception
behandeln
Im Normalfall möchten wir nicht, dass eine Anwendung beendet wird, nur weil eine
Exceptio
aufgetreten ist. Um dies zu erreichen, muss die Exception
an geeigneter Stelle im Programm behandelt werden. Erreichen tun wir dies, indem wir
die Methode, welche eine Exception
werfen, kann in einem try
- Block
definieren. Im Anschluss folgt ein catch
- Block, indem eine geworfene
Exception
behandelt werden kann.
Das nachfolgende Beispiel HandleException
zeigt grundlegend diese Vorgehensweise.
import java.io._ object HandledException { def main(args: Array[String]){ try { val is = new FileInputStream("c:\\test.txt") } catch{ case fnfe : FileNotFoundException => println("FileNotFoundException catched") } } }
Mehrere Exception
behandeln
Möchten wir mehrere Exception
nach einem try
-Block behandeln
geschieht das in Scala in einem catch
-Block. Die unterschiedliche
Behandlung unterschiedlicher Exception
erreichen wir über die Anwendung
des Pattern Matchings. Im nachfolgenden Beispiel erreichen wir unterschiedliche
Ausgaben auf der Systemausgabe je nach aufgetretenen Typ der Exception
.
Sollte in den case
Anweisungen kein passender Exception
Typ gefunden werden wird die Exception
über den Platzhalter
"_" gefangen und es erfolgt die Ausgabe, dass ein unbekannter Fehler
aufgetreten ist.
import java.io.FileNotFoundException object MoreThanOneException { def main(args: Array[String]) { try { throw new IllegalArgumentException } catch { case fnfe : FileNotFoundException => println("FileNotFoundExcepton catched") case npe : NullPointerException => println("NullPointerException catched") case iae : IllegalArgumentException => println("IllegalArgumentException catched") case _ => println("Unknwon error raised") } } }
Aufräumarbeiten - finally
Schließen wir einen Quelltextteil, in dem eine Exception
geworfen
werden kann, in einem try
-Block ein, können wir mit der finally
-Klausel
Aktionen definieren, die in jedem Fall ausgeführt werden. Die Anweisung bzw. der
Anweisungsblock, welcher der finally
-Klausel zugeordnet ist, wird ausgeführt,
egal ob eine Exception
geworfen wird oder nicht.
Die Verwendung der finally
-Klausel bietet sich besonders an, um z.B. offene
Dateien zu schließen oder Datenbankverbindungen zu trennen.
import java.io.FileNotFoundException object MyFinally { def main(args: Array[String]) { println("Start") try { println(compute(3.0,2.0)) println(compute(4.0,0.0)) println(compute(5.0,2.0)) } finally { println("cleanup efforts") } println("End") } def compute(denumerator: Double, numerator: Double) : Double = { require(numerator != 0.) denumerator / numerator } }
Der Ablauf des Programms führt zu folgender Ausgabe auf der Systemausgabe:
Start 1.5 cleanup efforts Exception in thread "main" java.lang.IllegalArgumentException: requirement failed at scala.Predef$.require(Predef.scala:145) at MyFinally$.compute(MyFinally.scala:18) at MyFinally$.main(MyFinally.scala:8) at MyFinally.main(MyFinally.scala)