Fire Events and Stay Bug Free #94
Chapter 12, Miscellany
|
473
HACK
The Problem
To illustrate the problem and its various solutions, consider the listener class
in Example 12-11.
This listener hangs on to a
String and prints that string to standard out
when
handleEvent( ) is called. Also, if the string is a specific value—C in this
case—it removes itself from the event source. If you can see why that’s going
to be a big deal, congratulations. If not, read on.
Next, define an abstract class to exercise various means of firing the event.
This is shown in Example 12-12.
This abstract class requires subclasses to include
addListener( ),
removeListener( ), and fireEvent( ) methods. It also implements a test
method that creates five listeners, identified as the letters
A through E, and
fires an event to each one.
Example 12-11. A simple event listener
import java.util.*;
public class TestEventListener extends Object
implements EventListener {
String id;
public TestEventListener (String id) {
this.id = id;
}
public void handleEvent (EventObject o) {
System.out.println (id + " called");
if (id.equals ("C")) {
((TestEventSource) o.getSource( )).removeListener (this);
}
}
}
Example 12-12. Abstract class for testing event-firing techniques
public abstract class TestEventSource {
public abstract void addListener (TestEventListener l);
public abstract void removeListener (TestEventListener l);
public abstract void fireEvent (java.util.EventObject o);
public void test( ) {
addListener (new TestEventListener ("A"));
addListener (new TestEventListener ("B"));
addListener (new TestEventListener ("C"));
addListener (new TestEventListener ("D"));
addListener (new TestEventListener ("E"));
fireEvent(new java.util.EventObject(this));
}
}
474
|
Chapter 12, Miscellany
#94 Fire Events and Stay Bug Free
HACK
Now, to show why the obvious way of firing the event is wrong, consider
the
PathologicalIteratingEventSource in Example 12-13. This does exactly
what the introduction to this hack advocated—it has an
ArrayList
to hold
the listeners, and it uses an
Iterator
to fire off the event to the listeners.
So, what happens when you run it? Here’s the output:
[tonberry] cadamson% java PathologicalIteratingEventSource
A called
B called
C called
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(
AbstractList.java:448)
at java.util.AbstractList$Itr.next(AbstractList.java:419)
at PathologicalIteratingEventSource.fireEvent(
PathologicalIteratingEventSource.java:19)
at TestEventSource.test(TestEventSource.java:11)
at PathologicalIteratingEventSource.main(
PathologicalIteratingEventSource.java:27)
Example 12-13. Iterating over listeners to fire events
import java.util.*;
public class PathologicalIteratingEventSource
extends TestEventSource {
ArrayList listeners = new ArrayList( );
public void addListener (TestEventListener l) {
listeners.add (l);
}
public void removeListener (TestEventListener l) {
listeners.remove (l);
}
public void fireEvent (EventObject o) {
Iterator it = listeners.iterator( );
while (it.hasNext( )) {
TestEventListener l = (TestEventListener) it.next( );
l.handleEvent (o);
}
}
public static void main (String[] args) {
PathologicalIteratingEventSource pies =
new PathologicalIteratingEventSource( );
pies.test( );
}
}

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.