Freitag, 9. August 2013

java.lang.NoClassDefFoundError - Aufklärung

Eine der bösesten in Java-Welt Exception ist

java.lang.NoClassDefFoundError: Could not initialize class ...


Dann weist man sofort, dass der Tag gelaufen ist und die Suche nach dem tatsächlichen Fehler ein nächtliches Debugging mit sich bringt.

Tja, dann versuchen wir an diese Stelle herauszufinden warum der Fehler so BÖSE ist, was die meiste Ursache hierfür sind und wie man es mit präventiven Maßnahmen vorbeugen kann.


Der Fehler wird so stark befurchtet vor allem wegen seinem un-sprechenden Namen. NoClassDefFoundError - was soll das schon heißen!? Sogar die Königin der Exceptions - NullPointerException - ist eindeutiger. Außerdem wird NoClassDefFoundError häufig mit dem ClassNotFoundException verwechselt und entsprechend - bekämpft man sie mit den Heilmitteln, die für das zweite pharmaziert wurden.


Die Ursache für dieses Error ist ganz trivial - die Klasse, also aufpassen die KLASSE und nicht das Objekt, könnten nicht initialisiert werden. Die Betonnung liegt dabei auf der KLASSE, weil der Error wird durch fehlerhafte Initialisierung der Attributen der Klasse verursacht. Und, wie wir alle wissen, Attribute der Klasse sind statischen Attribute (Felder).

Ein gutes Beispiel ist der Logger. Der Logger wird meistens als statisches Attribut definiert in etwa so:


public class Tester {
private static Logger log = Logger.getLogger(Tester.class);
...
}

Wenn der Logger nicht initialisiert werden kann, warum auch immer, dann kann auch die Klasse Tester nicht initialisiert werden.
Am Rande: Häufig kann der Logger nicht initialisiert werden, weil hier tatsächlich die Logger-Klasse im Classpath nicht eingebunden ist also kann die Logger-Klasse nicht geladen werden. Das ist jedoch, wie schon erwähnt, am Rande unseres Problem, da an der Stelle ist es unwichtig warum die Logger.getLogger(...) Methode eine Exception produziert hat.

Bei dem  alle ersten Zugriff auf die Tester-Klasse (z.B. über den Konstruktor new Tester()) stellt JVM, dass die Klasse Tester nicht initialisiert werden kann und merkt sich das. Ab dem zweiten Aufruf wird stets die NoClassDefFoundError Fehler produziert. Der eigentliche Fehler, dass die Logger.getLogger(...)-Methode bei dem aller ersten Aufruf fehlerhaft funktioniert hat, wird nicht mehr sichtbar.

Präventive Maßnahmen:
Die triviale Lösung fliest aus der Ursache des Problems heraus. Man sollte vermeiden statische Attributen direkt zu initialisieren.

Hier hab ich zwei Klassen verglichen, die einen Singelton abbilden, also sich selbst als statischen Attribut beinhalten.
In der ersten Klasse wird das statische Attribut zur Ladezeit der Klasse initialisiert:



Zweite Klasse initialisiert Singelton über die getInstance() Methode:



Und zum Schluss laden wir jeweils zwei Mal unsere beide Probanden  und schauen was dabei passiert:


Anbei die Konsole-Ausgaben:

Wie wir sehen - bei dem Laden der erste Klasse zum zweiten Mal kommt das NoClassDefFoundError Fehler.
Jedoch bei der zweiten Variante, wo das statische Attribute jedes Mal zur Abfragezeit geladen wird, bekommen wir stets sprechende Fehlermeldung, so dass die Ursache des Problems sofort identifiziert wird.

סוֹף~

1 Kommentar:

Anonym hat gesagt…

Danke, sehr nutzlich!