Inhalt
- Vorschläge zum Exception Handling
- Vorschläge zum Logging
Vorschläge zum Exception Handling
Optimal wäre, wenn der Aufrufer aus der Exception programmatisch folgende Fragen beantwortet bekäme:
- Fachliche 'Application Exception' oder technische 'System Exception'?
- Soll Eintrag in Logging-Datei erfolgen oder ist bereits geloggt?
- Muss laufende Transaktion abgebrochen und Rollback eingeleitet werden?
- Muss eine Session (z.B. eine Hibernate-Session) beendet werden (weil inkonsistent)?
- Muss Anwendung beendet werden (weil unrecoverable)?
- Welcher Fehler, warum und wo?
Es folgen Vorschläge zur Annäherung an dieses Ziel.
Dabei beziehen sich allerdings viele Vorschläge auf eine Java-EE-Application-Server-Umgebung
und müssen für das eigene Projekt umdefiniert werden.
Das gewählte Exception-Handling- und Logging-Konzept sollte schriftlich dokumentiert werden
und allen Projektbeteiligten bekannt sein.
Serverseitig 'checked Exception' versus 'unchecked RuntimeException'
- Einsatz von 'unchecked RuntimeException', wenn laufende Transaktion abgebrochen werden soll
- Einsatz von 'checked Exception' andernfalls
Clientseitig 'checked Exception' versus 'unchecked RuntimeException'
- Einsatz von 'unchecked RuntimeException' bei technischer 'System Exception'
- Einsatz von 'checked Exception' bei fachlicher 'Application Exception'
Informationsgehalt der Exceptions
- Es sollten keine Exceptions ohne Aussage geworfen werden wie zum Beispiel:
throw new RuntimeException();
throw new Exception( "Darf nicht auftreten." );
- Da wo möglich sollte der Konstruktor mit zwei Parametern verwendet werden:
throw new MeineException( String message, Throwable cause );
- Exceptions sollten eindeutige Exception-Typen und verständliche Meldetexte haben.
'Exception' und 'RuntimeException' sollte nicht direkt geworfen werden, sondern nur davon abgeleitete Klassen.
Dies können Standardklassen sein
(für 'RuntimeException' z.B. IllegalArgumentException, IllegalStateException,
MissingResourceException, NoSuchElementException, ProviderException, UnsupportedOperationException)
oder eigene Klassen, zum Beispiel so:
public class MeineException extends Exception // oder RuntimeException
{
public MeineException() { super(); }
public MeineException( String message ) { super( message ); }
public MeineException( Throwable cause ) { super( cause ); }
public MeineException( String message, Throwable cause ) { super( message, cause ); }
}
'NullPointerException'
- Es sollten zusätzliche Abfragen implementiert werden,
um eine 'NullPointerException' zu vermeiden,
da sie manchmal schwer zu lokalisieren ist,
weil der Meldetext keinen genauen Hinweis auf die Fehlerquelle liefert.
- 'public'-Methoden sollten Argumente auf Gültigkeit überprüfen und
bei unerlaubten oder 'null'-Argumenten z.B. eine 'IllegalArgumentException' werfen.
Besonderheiten bei SQL und ORM
- JDBC verwendet 'checked Exceptions'.
- JDO, TopLink und
Spring-JdbcTemplate
werfen ausschließlich 'unchecked RuntimeExceptions'.
- 'HibernateExceptions' sind bis
Hibernate
Version 2.x 'checked Exceptions',
also keine 'RuntimeExceptions', aber ab Hibernate Version 3.x 'unchecked RuntimeExceptions'
(nach dem Auftreten einer 'HibernateException' muss sofort eine eventuell laufende Transaktion
für Rollback markiert werden und es muss die Hibernate-Session gelöscht werden,
da sie inkonsistent sein kann).
Test
- Überprüfen Sie das Werfen korrekter Exceptions im
'JUnit'-Test mit der
'fail()'-Methode.
- Testen Sie das Verhalten bei Störungen während Transaktionen und das Funktionieren des Rollbacks.
- Testen Sie auch das Logging.
- Erwägen Sie den Einsatz von 'assert'
(ab Java 1.4, Aktivierung mit '-ea', z.B. für Parametertest bei private-Methoden)
oder auch das aufwändigere DBC (Design by Contract, z.B. mit 'iContract').
Vorschläge zum Logging
Allgemeine Vorschläge
Logging (z.B. in eine .log-Datei oder in eine SQL-Datenbank) ist eine große Hilfe sowohl während der Entwicklungszeit als auch später zur Fehlersuche beim Kunden.
Logger erlauben das selektive Ein- und Ausschalten bestimmter oder aller Log-Meldungen zur Laufzeit über eine einfache textbasierte Steuerdatei.
Bewährt haben sich folgende Vorschläge:
- Verlassen Sie sich nicht auf das sehr rudimentäre und nur für bestimmte Exceptions
durchgeführte Logging des Application Servers
(normalerweise nur für unchecked RuntimeExceptions, die bis zum EJB-Container gelangen).
- Verwenden Sie kein Logging per 'System.out.println("...");',
die Konsole ist nicht immer sichtbar und solche Ausgaben sind nicht zur Laufzeit konfigurierbar.
- Verwendung von Log4j.
- Alle unerwarteten Exceptions sollten zu einem Logging-Eintrag führen.
- Zusätzlich können Auslastungs- und Performancekennzahlen sinnvoll sein.
- Umlaute (ä, ö, ü) und deutsche Sonderzeichen (ß, §, €) sollten vermieden werden.
- Falls Ausgabe in Datei: Jede Meldung produziert genau eine Zeile, damit 'grep' verwendet werden kann (Ausnahme: StackTrace).
- Wichtig ist eine einheitliche Struktur der Logging-Meldungen, damit sie mit Tools ausgewertet werden können.
- Definition stets zu verwendender 'Rubriken':
Bei Ausgabe in SQL-Datenbank entsprechen die Rubriken den Tabellenspalten,
bei Ausgabe in Datei werden Rubriken durch Semikolons getrennt (.csv-Datei, kann direkt z.B. in Excel bearbeitet werden).
- Die Rubriken können zum Beispiel sein (in Application-Server-Umgebung):
Zeitstempel; Anwendungsname; Thread-Name; Log-Level; Exception-ID; Fehlercode; Meldetext.
- Der Zeitstempel (Timestamp) formatiert nach ISO 8601 (EN 28601, DIN 5008), also beginnend mit dem Jahr (z.B. 'yyyy-MM-dd HH:mm:ss.SSS'),
damit einheitlich mit Tools ausgewertet werden kann und damit nach Datum sortiert werden kann.
- Damit in mehrschichtigen Multithreading-Umgebungen zusammengehörende Exceptions identifiziert werden können, kann eine 'Exception-ID' (automatisch) generiert werden.
Auch sollte doppeltes Logging vermieden werden. Siehe hierzu:
'http://www-128.ibm.com/developerworks/java/library/j-ejbexcept.html'.
- Fehler, die möglicherweise zum Beispiel vom System-Operator bearbeitet werden müssen, sollten eindeutige Fehlercode-Nummern erhalten, zu denen in einer Dokumentation das weitere Vorgehen beschrieben ist.
- Falls Fehlermeldungen oder Logging-Meldungen mehrsprachig sein sollen,
verwenden Sie statt der Meldetexte Fehlernummern, die dann über .properties-ResourceBundles aufgelöst werden.
Logging-Level
Beim Logging wird den Meldungen ein Logging-Level mitgegeben.
Diese Level sollten möglichst standardisiert verwendet werden, um die Auswertung der Meldungen zu vereinfachen.
Vorschläge für entsprechende Vorgaben für serverseitiges Logging können sein:
Logging- Level | Anwendung | Beispiele |
FATAL |
Schwerwiegende Fehler, von denen sich das System oder die Anwendung nicht erholen kann und beendet werden muss ("Unrecoverable Error") |
Sollte eigentlich nur vom System (Application Server) generiert werden, z.B. "OutOfMemory" in kritischen Softwareteilen |
ERROR |
Fehlermeldungen, auf die der Operator oder Administrator reagieren muss |
Fehler in der Netzwerkverbindung, Datenbank-Connection oder aus der LDAP-Benutzerverwaltung |
WARN |
Meldungen, die vom Operator an die Softwareentwicklungsabteilung übermittelt werden müssen und dort analysiert werden müssen, die aber den Betrieb wahrscheinlich nicht beeinträchtigen |
Meldungen zu unerwarteten oder inkonsistenten Datenbankinhalten, "IllegalArgumentException", "NullPointerException" |
INFO |
Hinweise |
Für den laufenden Betrieb möglicherweise interessante Meldungen, zum Beispiel zur Auslastung und Performance |
DEBUG |
Nur für den Softwareentwickler interessante Meldungen |
Diese Meldungen sind im laufenden Betrieb ausgeschaltet, können aber bei Bedarf zur Laufzeit selektiv "packageweise" eingeschaltet werden, um bestimmte Fehlerursachen aufzuspüren |
Programmierung
Das Einfügen von Logging im Java-Sourcecode gestaltet sich sehr einfach, zum Beispiel so:
import org.apache.log4j.Logger;
public class MeineKlasse
{
private static final Logger LOGGER = Logger.getLogger( MeineKlasse.class );
void meineMethode() throws MeineException
{
try {
// ...
} catch( Exception ex ) {
LOGGER.warn( "Mein Logging-Meldetext." );
throw new MeineException( "Mein Fehlermeldetext.", ex );
}
}
}
- Weiteres hierzu finden Sie unter Log4j.
Weitere Themen: andere TechDocs
| Coding Conventions
| Log4j
© 2002-2007 Torsten Horn, Aachen