Sehen wir uns noch mal das letzte Kapitel an. Dort haben wir Methoden in unserer Wirtschaft angelegt, durch die ein Gast das Gasthaus betreten und verlassen kann. Falls dies schief läuft (Gast ist nicht in der Wirtschaft, Wirtschaft voll), wird in unserer Klasse Wirtschaft eine Meldung ausgegeben (wenn überhaupt) und sonst nichts. Dadurch nehmen wir der aufrufenden Methode die Möglichkeit auf solche Ereignisse zu reagieren. Dies wollen wir in diesem Kapitel ändern.
Sie haben es bereits erraten! Dieses Kapitel dreht sich um Fehlerbehandlung. Sehen wir uns zuerst die Situation an, wenn die Wirtschaft voll ist.
public void betreten(Gast g) {
for (int i = 0; i < this.plaetze.length; i++) {
if (this.plaetze[i] == null) {
System.out.println("Willkommen " + g);
this.plaetze[i] = g;
return;
}
}
System.out.println("Kein Platz mehr frei");
}[/sourcecode]
Natürlich ist ein <code>System.out.println</code> keine akzeptable Rückmeldung! Anstelle dieser Ausgabe könnten wir eine <strong>Fehlermeldung</strong> werfen. Aber ist das in diesem Fall wirklich sinnvoll? Ist es wirklich eine Ausnahme bzw. ein Problem und so ungewöhnlich, dass eine Wirtschaft voll besetzt ist? <strong>Nein</strong>, ist es nicht! Deshalb ist es an dieser Stelle weitaus sinnvoller lediglich den Rückgabewert der Methode so zu verändern, dass ein <code>boolean</code> zurückgegeben wird. Ist der Rückgabewert <code>true</code>, hat sich der <code>Gast</code> erfolgreich an einen Platz gesetzt. Ist er <code>false</code>, ist leider kein Platz mehr frei. Modifizieren wir den Code dieser Methode also wie folgt:
[sourcecode language="java"]public boolean betreten(Gast g) {
for (int i = 0; i < this.plaetze.length; i++) {
if (this.plaetze[i] == null) {
System.out.println("Willkommen " + g);
this.plaetze[i] = g;
return true;
}
}
return false;
}[/sourcecode]
Da wir nun keine Ausgabe mehr in unserem Programm haben, wenn ein Gast keinen Platz mehr findet, müssen wir die aufrufende Methode in der Klasse <code>Welt</code> noch modifizieren. Wir prüfen hierbei den Rückgabewert von <code>betreten</code> und geben im Falle einer vollen <code>Wirtschaft</code> einen entsprechenden Text aus.
[sourcecode language="java"]private static void gastKommt(Gast g) {
if (g.isDurstig() || g.isHungrig()) {
if (!Welt.zumJavaBlogBuch.betreten(g)) {
System.out.println(g + " findet leider keinen Platz mehr");
}
}
else {
System.out.println(g + " hat keinen Hunger und auch keinen Durst");
}
}
Als nächsten Schritt sollten wir die Routine überarbeiten, wenn ein Gast die Wirtschaft wieder verlässt. Die Implementierung sieht momentan so aus:
public void verlassen(Gast g) {
for (int i = 0; i < this.plaetze.length; i++) {
if (this.plaetze[i] == g) {
System.out.println("Auf Wiedersehen " + g);
this.plaetze[i] = null;
return;
}
}
}[/sourcecode]
Natürlich ist es in diesem kleinen Beispiel nicht zwingend nötig darauf zu reagieren, wenn ein Gast nicht in der Wirtschaft ist. Zu einem späteren Zeitpunkt könnte dieses Wissen aber mehr Wert werden. Doch wie sollten wir in diesem Fall reagieren? Auch mit einem anderen Rückgabewert, oder doch mit einer <code>Exception</code>? Vergleichen wir die beiden Fälle. Es ist völlig normal und auch ohne Probleme möglich, dass ein Gast eine Wirtschaft betreten möchte, und dabei feststellt, dass kein Platz mehr frei ist. Es ist allerdings alles andere als normal und auch nicht möglich, dass ein Gast ein Gasthaus verlässt, in welchem er sich gar nicht befindet. Es handelt sich also um einen <strong>Fehler</strong> bzw. um eine <strong>Ausnahme</strong>.
Zur Reaktion auf diese Gegebenheit sollten wir also eine <code>Exception</code> werfen. Hierzu müssen wir uns zuerst einmal eine entsprechende anlegen (es ist höchst unwahrscheinlich, dass es in Java eine Standard-Exception für dieses Verhalten gibt).
Diese Fehlermeldung sollte einen Text enthalten, um den Fehler näher zu beschreiben. Ansonsten sind keine Eigenschaften notwendig. Es genügt also eine Klasse, die von <code>Exception</code> erbt, und den Konstruktor mit dem Übergabeparameter einer Nachricht der Elternklasse aufruft.
[sourcecode language="java"]package de.jbb.ausnahmen;
public class GastNichtAnwesend extends Exception {
public GastNichtAnwesend(String arg0) {
super(arg0);
}
}
Nun müssen wir den Methodenkopf unserer verlassen-Methode so erweitern, dass von dieser Methode die eben programmierte Fehlermeldung geworfen werden kann.
public void verlassen(Gast g) throws GastNichtAnwesend {
Natürlich dürfen Sie auch nicht vergessen, diesen Fehler dann ggf. auch über throws zu werfen. Nach den Veränderungen sieht unsere Methode nun so aus:
public void verlassen(Gast g) throws GastNichtAnwesend {
for (int i = 0; i < this.plaetze.length; i++) {
if (this.plaetze[i] == g) {
System.out.println("Auf Wiedersehen " + g);
this.plaetze[i] = null;
return;
}
}
throw new GastNichtAnwesend(g + " befindet sich nicht im Gasthaus");
}[/sourcecode]
Als letzten Schritt müssen wir die Fehlermeldung in unserer <code>Welt</code>-Klasse mit einem <strong>try-catch-Block</strong> abfangen. Tritt eine solche Fehlermeldung auf, wird der Fehler ausgegeben. Hierzu verwenden wir den <strong>Error-Stream</strong>, welchen wir mittels <code>System.err.println</code> anstelle von <code>System.out.println</code> einsetzen. Dadurch können wir (oder ein Logging-Tool) unterscheiden, ob es sich um eine normale Systemausgabe oder eine Fehlermeldung handelt.
[sourcecode language="java"]private static void gastGeht(Gast g) {
try {
Welt.zumJavaBlogBuch.verlassen(g);
}
catch (GastNichtAnwesend gna) {
System.err.println("Problem beim Verlassen:");
System.err.println(gna.getMessage());
}
}
