René Link René Link - 3 years ago 190
Java Question

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

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?

Answer Source

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.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download