O'Reilly logo

Swing Hacks by Chris Adamson, Joshua Marinacci

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

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( );
}
}

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required