Java Puzzler: Ch-Ch-Ch-Changes

by Robert Cooper

In the spirit of Neil and Josh/Will's Java Puzzlers, here is one I just recently ran into:

Given the following block of code:

PropertyChangeSupport changes = new PropertyChangeSupport(this);
PropertyChangeListener l = new PropertyChangeListener(){

public void propertyChange(PropertyChangeEvent evt) {
throw new UnsupportedOperationException("Not supported yet.");
}

};
changes.addPropertyChangeListener("foo", l);

for( PropertyChangeListener remove : changes.getPropertyChangeListeners() ){
changes.removePropertyChangeListener(remove);
}

System.out.println(changes.getPropertyChangeListeners().length);


What will this snippet print:

  1. 0
  2. 1
  3. Throws an Exception
  4. Other


Answer after the jump.

6 Comments

qinxian
2007-12-14 05:39:53
Hi, I try it at JAVA6, the answer is 0.
bob
2007-12-14 06:23:26
gives me 0 with 1.5.0_09 too
Mark
2007-12-14 10:56:09
Yup. I guessed 0, ran it, and got 0...
cooper
2007-12-17 14:55:48
Interesting. Yeah. I get differing results between JVMs!



cooper
2007-12-17 14:58:32
Wait. This gets weirder.


Something changes when you call the getPropertyChangeListeners(). Running 1.5 on my Mac, the above code returns 0. This code, however, returns 1.


Main(){
PropertyChangeSupport changes = new PropertyChangeSupport(this);
PropertyChangeListener l = new PropertyChangeListener(){


public void propertyChange(PropertyChangeEvent evt) {
throw new UnsupportedOperationException("Not supported yet.");
}


};
changes.addPropertyChangeListener("foo", l);


changes.removePropertyChangeListener(l);
System.out.println(changes.getPropertyChangeListeners().length);


}

bob
2007-12-18 04:34:46

I suspect, as you alluded to in the original post, it has something to do with the fact that in your second example, the "listener" that gets stored in the PropertyChangeListeners list is an instance of java.beans.PropertyChangeListenerProxy (verified by printing out getClass().getCanonicalName() for the entries in the getPropertyChangeListeners() list). ie. it's a different object to the one that was inserted into the array, so attempting to remove your original object will fail.


On the face of it, it does appear a bit counter-intuitive, and the API is not particularly well specified (see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4937059 for some other examples of problems with the PropertyChangeSupport documentation).