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 String
s 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?
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.