s10 – Fehlerbehandlung

 

In jedem Programm kann es zu Fehlern kommen, selbst wenn der Programmierer alles richtig gemacht hat. Die Fehler können zum Beispiel aus einem falschen Format der Eingabe des Users oder fehlenden Resourcen (Datei nicht vorhanden, lesen am Dateiende, …) resultieren.
Java “wirft” diese Fehler dann aus und es bleibt dem Programmierer überlassen, ob er sein Programm darauf vorbereitet hat, mit der Fehlermeldung umzugehen.

Es wird zwischen zwei Fehlertypen unterschieden:

  • Exception: Ausnahme, behebbarer Fehler
  • Error: fataler Fehler

Beispiel:

import java.io.*;

class Fehlerbehandlung
{
	public static void main (String[] args)
	{
		int iZahl = Integer.parseInt(args[0]);
		System.out.println("Übergebene Zahl: "+iZahl);
	}
}

Es können zwei verschiedene Fehler auftreten:

  • Das Programm wurde ohne Parameter aufgerufen, das Array args ist daher leer. Der Zugriff auf das erste (fehlende) Element verursacht einen Speicherfehler, nämlich eine “ArrayIndexOutOfBoundsException”
  • Der erste übergebene Parameter war keine ganze Zahl sondern eine andere Zeichenkette, z.B. “asd581723″, daher konnte der Parameter nicht in einen Integer umgewandelt werden und es wird eine “NumberFormatException” ausgeworfen

Es gibt nun Fehler, um die sich der Programmierer kümmern sollte und solche, bei denen eine Fehlerbehandlung wenig Sinn macht. Beispiele für letztere:

  • “OutOfMemoryError” oder “StackOverflowError”-Wenn kein Speicher mehr zur Verfügung steht, kann der Programmierer da auch nichts dran ändern
  • “InternalError” oder “UnknownError”-solche Fehler sind zu allgemein und können daher zur Laufzeit nicht sinnvoll behandelt werden

Beispiele für Fehler, bei denen der Aufwand der Fehlerbehandlung den praktischen Nutzen häufig übersteigt:

  • ArithmeticException, NullPointerException
  • ArrayIndexOutOfBoundsException, NumberFormatException-Manchmal sollte man auch zu Gunsten der Übersichtlichkeit des Programmtextes darauf vertrauen, dass der Benutzer weiß, wie er mit dem Programm umzugehen hat. Fehler seitens des Users können auch durch eine ausführliche Programmdokumentation verhindert werden.

Die Standard-Ausnahmebehandlung von Java

Wenn sich der Programmierer nicht um Fehler kümmert, tut Java das automatisch. Die Fehlerbehandlung beschränkt sich dabei allerdings darauf, dass der Typ des Fehlers und die Stelle im Programmtext, an dem er aufgetreten ist, ausgegeben wird. Nicht abgefangene Fehler werden also mit einem Programmabbruch bestraft.

Fehlerbehandlung für das obige Beispiel:

class Fehlerbehandlung
{
	public static void main (String[] args)
	{
		try
		{
			int iZahl = Integer.parseInt(args[0]);
			System.out.println("Übergebene Zahl: "+iZahl);
		}
		catch(NumberFormatException e)
		{
			System.out.println("Der Parameter hatte ein ungültiges Format");
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			System.out.println("Es muss ein Parameter übergeben werden");
		}
	}
}

Um manuell einen Fehler abzufangen, schreibt man alle kritische Befehle in einen try-Block
Wenn es in diesem Block dann zu einem Fehler kommt, wird der catch-Block ausgeführt. Try-Blöcke können auch ineinander verschachtelt sein. Wenn auf verschiedene Ausnahmen unterschiedlich reagiert werden soll, können hinter einem try-Block mehrere catch-Blöcke stehen. Wird in dem try-Block dann kein Fehler ausgeworfen, werden alle catch-Blöcke übersprungen. Kommt es zu einem Fehler, wird der erste passende catch-Block aufgerufen, die nachfolgenden werden übersprungen. Wird kein passender Exception-Handler (catch-Block) gefunden, wird geprüft, ob es einen äußeren try-Block gibt, an den der Fehler weitergeleitet werden kann. Gibt es keinen äußeren mehr, wird die Standardfehlerbehandlung von Java verwendet.
Das obige Beispiel könnte wie folgt geschachtelt programmiert werden:

class Fehlerbehandlung
{
	public static void main (String[] args)
	{
		try
		{
			try
			{
				int iZahl = Integer.parseInt(args[0]);
				System.out.println("Übergebene Zahl: "+iZahl);
			{
			catch(NumberFormatException e)
			{
				System.out.println("Der Parameter hatte ein ungültiges Format");
			}
		}
		catch(ArrayIndexOutOfBoundsException e)
		{
			System.out.println("Es muss ein Parameter übergeben werden");
		}
	}
}

Statt einem catch-Block oder hinter dem letzten catch-Block kann noch ein “finally-Block” stehen, der auf jeden Fall ausgeführt wird, unabhängig davon ob

  • keine Ausnahme ausgeworfen wird
  • der try-Block durch ein return verlassen wird
  • eine Ausnahme ausgeworfen wird, die durch ein catch abgefangen wird
  • eine Ausnahme ausgeworfen wird, die nicht durch ein catch abgefangen wird

Die throws-Klausel

Wenn in einer Methode oder Funktion ein Fehler auftreten kann, der nicht durch einen try-catch-Algorithmus abgefangen wird, kann der Fehler auch an die Stelle weitergereicht werden, die die Methode oder Funktion aufgerufen hat. Dazu muss in der Deklaration der Methode hinter der Liste der Parameter noch ein “throws …” stehen, wobei das … eine Liste von Typen ist, die alle Subtypen von “throwable” sind. Beispiel:

public int Eingabe(String s) throws IOException
{...}