Here Be Dragons oder: Ein Blick in den Java Code

Seit einigen Tagen rätsele ich, warum mein selbsimplementiertes Java Swing TreeModel nicht richtig funktioniert. Bei der Ursachenforschung bin ich heute dann mal in den Orginalcode von Java abgetaucht um zu sehen, was dort vielleicht anders gemacht wird. Dabei bin ich auf einige Codeperlen gestossen, für die man bereits im Softwaremittelalter auf dem Scheiterhaufen gelandet wäre…

In EventListenerList.class gibt es die Methode
public synchronized <T extends EventListener> void add(Class<T> t, T l)

Sie beginnt mit einem Null-Check:

if (l==null) {
// In an ideal world, we would do an assertion here
// to help developers know they are probably doing
// something wrong
return;
}

Der Kommentar ist natürlich großartig: Wieso wird dort nicht wirklich eine selbsterklärende Exception geschmissen? Warum will man den Entwicklern nicht helfen?

Als nächstes wird geprüft, ob die übergebene Klasse t auch zum übergebenen Listener l paßt:

if (!t.isInstance(l)) {
throw new IllegalArgumentException("Listener " + l + " is not of type " + t);
}

Warum setzt man nicht gleich lokal t=l.getClass() und läßt den Aufrufparameter weg? Mir fällt kein Fall ein, der den obigen Check erfüllt und nicht mittels getClass() erledigt werden könnte.

Und dann das:

// Otherwise copy the array and add the new listener
int i = listenerList.length;
Object[] tmp = new Object[i+2];
System.arraycopy(listenerList, 0, tmp, 0, i);
tmp[i] = t;
tmp[i+1] = l;
listenerList = tmp;

Notieren wir mal:
1. Wildes Arraykopieren statt einer Liste
2. Statt eines sauberen ListenerEntry-Objekts mit den Attributen Typ und Referenz wird hier mit untypisierten Arrays gearbeitet und die Daten werden per Index verteilt. Jeder Verwender muß also wissen, daß er das Array in Zweierschritten durchlaufen muß.
3. Oben noch nicht sichtbar: aber die Zweierschrittstruktur des Arrays wird auch so nach aussen gegeben. Als Beispiel hier ein Aufruf durch DefaultTreeModel.class:

// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
TreeModelEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==TreeModelListener.class) {
// Lazily create the event:
if (e == null)
e = new TreeModelEvent(source, path,
childIndices, children);
((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
}
}

Und da in EventListenerList.class schon eine Filterfunktion public <T extends EventListener> T[] getListeners(Class<T> t) eingebaut ist wäre es nicht einmal nötig, daß DefaultTreeModel.class selber filtert…

P.S.: Alle Einrückungen wurden von WordPress vernichtet 😉
P.S.2: Jetzt sieht man auch, warum Einrückungen gut sind und daß man unbedingt auch einzeilige Conditionalstatements als Blöcke klammern sollte.

Advertisements
This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s