Sunday, July 29, 2007

Java Exception Handling Antipattern

Der Artikel "Exception-Handling Antipattern" auf java.net erklärt wie Exceptions in Java verwendet und nicht verwendet werden sollten.

Der Artikel ist für jeden Java-Entwickler lesenswert. Die in dem Artikel genannten Antimuster sind:

  • Log and Throw
  • Throwing Exception
  • Throwing the Kitchen Sink
  • Catching Exception
  • Destrutice Wrapping
  • Log and Return Null
  • Catch and Ignore
  • Throw from within Finally
  • Multi-Line Log Messages
  • Unsupported Operating Returning Null
  • Ignoring InterruptedException
  • Relying on getCause()

Die Regeln sollten eigentlich (weitgehend) Common Sense sein, aber (nach leidvoller Erfahrung der letzten Monate) bin ich der Meinung, dass man kann selbst Common Sense nicht oft genug wiederholen.

Ich würde noch drei Empfehlungen hinzufügen, die vielleicht zu offensichtlich sind, aber dennoch irgendwie in die Liste passen. Java-Pros werden wahrscheinlich (zumindest für Empfehlung 1) Gegenbeispiele finden, aber grundsätzliche sind dies gute Ratschläe.

  1. Niemals Exceptionen von Error und Untertypen werfen.
    "Error" ist in der Regel einzig und allein der Virtuell Maschine und dem SDK vorbehalten sein und sollte so nur in Ausnahmefällen von Benutzercode gefangen werden. Schon gar nicht sollte Benutzercode Error-Exceptions werfen.
    In der Dokumentation zu Error heisst es:
    <blockquote>
      <p>An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.</p>
    </blockquote>
    
    <p>In der Regel verwendet man eine Error-Klasse für einen ganz anderen Zweck als in der Dokumentation angegeben, nur weil der Name passend klingt z.B. VerifyError für die Verifikation von Benutzereingaben. Eigene Exceptions oder RuntimeExceptions für problematische Zustände sind die oft die bessere Wahl.</p>
    
  2. System.exit() sollte nicht in catch aufgerufen werden.
    Ich gestehe zu, dass es von dieser Regel Ausnahmen geben kann, aber das Anliegen von Exceptionhandling ist, dass sich der Code um die Fehlerbehandlung kümmert, der weiß ein Fehler behandelt werden soll. Nur niemand eine Exception behandeln kann, soll das Programm beendet werden.

    <p>Wenn man System.exit() in catch aufruft, dann nehme ich Methoden weiter oben im Stack die Möglichkeit den Fehler zu behandeln. In der Regel ist dies nicht sinnvoll.</p>
    
    <p>System.exit() sollte in der Regel sowieso gemeiden werden, da z.B. alle Cleanup-Operationen nicht durchgeführt werden und der Code mit System.exit() mit einem Schlag quasi-untestbar wird.</p>
    
  3. Eine NullPointerException sollte nicht manuell geworfen werden.
    Eine NullPointerException ist eine wirklich meise Art von Exception, weil sie oft auf Fehler hinweisen, die an ganz anderen Stellen im Code verursacht wurden. Zum Beispiel sind NullPointerExceptions tief aus dem Code eines J2EE-Containers ist so das schlimmestem was passieren kann. Es ist nur schwer möglich den Grund für den Fehler zu suchen.

    <p>Wenn man den Gedanken hat durch "throw new NullPointerExcecption()" manuell eine NPE zu werfen, sollte man besser davon Abstand nehmen und eine Exceptionklasse wählen, die besser den wirklichen Fehler beschreibt z.B. IllegalArgumentException("xy is null").</p>
    

No comments:

Post a Comment