Property change event's old value for collections when element is added

702 Views Asked by At

I have a Java bean that has a collection property with a getter and also provides add methods for the collection.

So when the collection is modified using the add method I must fire a PropertyChangeEvent. A PropertyChangeEvent has an old value and a new value.

How do you handle the old value?

To make things easy I will use a collection of Strings here. E.g.

public class MyBean {

    private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
    private Set<String> names = new HashSet();

    // Delegate methods to add/remove PropertyChangeListeners are omitted here

    /**
     * The collection property
     */
    public Collection<String> getNames() {
        return Collections.unmodifiableCollection(names);
    }

    public void addName(String name){
          if(names.add(name)){
             Collection<String> oldValue = ????; // How do you get the old value
             Collection<String> newValue = Collections.unmodifiableCollection(names);
             pcs.firePropertyChange("names", oldValue, newValue);
          }
      }
}

One way to get the old value might be to create a copy before adding

public void addName(String name) {
    Collection<String> oldValue = new HashSet<>(names);
    if (names.add(name)) {
        Collection<String> newValue = Collections.unmodifiableCollection(names);
        pcs.firePropertyChange("names", oldValue, newValue);
    }
}

But in a lot of situations the old value might be copied for nothing.

So another thought was not to use the add method and instead use contains before

public void addName(String name) {
    if (names.contains(name)) {
        return;
    }

    Collection<String> oldValue = new HashSet<>(names);
    names.add(name);
    Collection<String> newValue = Collections.unmodifiableCollection(names);

    pcs.firePropertyChange("names", oldValue, newValue);
}

This works well with a Set. But when the names collection is an ArrayList it will not work, because an ArrayList can contain multiple instances of equal objects. So contains would return true, but an add would also return true.

In multi-threaded environments it might also be a problem to first check via contains and then add, because in the meanwhile another thread might have added the same object. But I don't want to introduce this complexity here. I just want to find a good design for a single threaded environment, usually when such beans are used in the UI (Event-Dispatch-Thread).

How do you handle the old value in such situations?

1

There are 1 best solutions below

0
On BEST ANSWER

You can use Map.putIfAbsent implementation, and have the key and value to be the same.

In case the key existed, the previous (old) value will be returned, and be used for firing the firePropertyChange. That works well in multithreaded environment, only one thread will be able to add a new entry.