• Post Reply Bookmark Topic Watch Topic
  • New Topic

Set or List?  RSS feed

 
Stevens Miller
Bartender
Posts: 1445
30
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I need to implement a list of listeners. Each one is registered by calling the add method of the object that will fire the events the listeners are interested in. Is there a basis upon which I might choose between using an actual list, like ArrayList, wherein a given listener could be added more than once, versus a set, like LinkedHashSet, wherein a given listener cannot be added more than once?

I suppose one answer might be, "If you want to be able to add a given listener more than once, use a list, if not, use a set," but that begs the question (by assuming I know which one I want to be able to do).

Is there any commonly practiced choice here?
 
Ron McLeod
Bartender
Posts: 1602
232
Android Angular Framework Eclipse IDE Java Linux MySQL Database Redhat TypeScript
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would use a Set since I can't see a valid scenario where the same handler should be called multiples for a particular event.

It also makes removing the listeners easy since you don't need to check how many times the handler had been registered, whether it had in-fact been registered at all, or if the remove method was passed a a reference to null -- simply listeners.remove(listener)
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stevens Miller wrote:. . . Is there any commonly practiced choice here?
No.

It seems unusual to have to make a List of Listeners to be listened to and nobody will listen to me unless I stop the allisteration.
Is there any reason to have the same Listener twice? Is there any reason to know the order they are added in? Don't Listeners lack the prerequisite for putting into a Collection, viz. overridden equals() and hashCode() methods? If you use the getXYZListeners method on a Component, you get an XYZListener[] array. Ron is correct; if the array doesn't suffice go for a Set.
 
Stevens Miller
Bartender
Posts: 1445
30
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, fellows. I like the Set better myself, so that's what I'll use.

Interestingly, the gods do not agree. I stepped into the code for JButton's addActionListener method. You end up in the EventListenerList's add method, which is this:

No redundancy check there, so duplicate listeners would be accepted. Also, Ron is correct: their remove method only removes one matching entry. Interestingly, it works its way backwards in the array, probably to be sure you remove the most recently added copy, in case your code relied on the calling order of the whole array of listeners, such that maybe the second time your duplicate is called it does something different than it did the first time.

Looking at Lines 22 and 23, it's kind of hard to imagine anyone wrote it that way. I would think, at a minimum, the array would be of objects that held the Class<T> reference and the T reference, rather than shuffling them together as alternating pairs.

Always interesting to look beneath the hood.
 
Campbell Ritchie
Marshal
Posts: 56536
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
How could you do a redundancy check when Listeners usually don't have overridden equals and hashCode methods?
And how are you going to pass the wrong Class<?> object so as to get that Exception thrown?
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16059
88
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Beware that when you use a HashSet (or LinkedHashSet) or TreeSet, the objects that you put in the Set have to have valid hashCode() and equals() methods.

A Set cannot contain duplicate objects. The hashCode() and equals() methods determine what it means for two objects to be equal.
 
Rob Spoor
Sheriff
Posts: 21135
87
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Except for TreeSet it's compareTo (or a Comparator), not equals and hashCode.
 
Stephan van Hulst
Saloon Keeper
Posts: 7973
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There's a good reason to use a List rather than a Set: There are cases where the client expects listeners to run in subscription order. If you want to enforce uniqueness of listeners, you have to use a LinkedHashSet. Here is a reusable type- and thread-safe component:
 
Rob Spoor
Sheriff
Posts: 21135
87
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stephan van Hulst wrote:

FYI, it's really bad practice to call unknown code (the handlers) in a synchronized block. From Effective Java, item 67: Avoid excessive synchronization:
As a rule, you should do as little work as possible inside synchronized regions.

A quick solution, which also solves a potential ConcurrentModificationException if a handler tries to remove itself, is to make a copy (inside a synchronized block):
Note that the second fire method contains duplicate synchronization on handlers - first for the empty check, then again in the called fire method. This makes it possible that after the second method calls the first one, the handlers are cleared and the snapshot will be empty. An alternative would be to create a third (private) fire method that takes the snapshot as extra argument:
 
Stephan van Hulst
Saloon Keeper
Posts: 7973
143
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're absolutely right Rob, have a cow.

I suppose in this case it would be much easier to implement the set using a CopyOnWriteArrayList. This might even make the class more performant, as it's likely that the handlers will be iterated much more than they will be added to.

When the Spliterator is created, a snapshot of handlers is made under the hood, which prevents the need for external synchronization.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!