属性 添加元素时更改集合事件的旧值

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

我有一个 Java bean,它有一个集合 属性 和一个 getter 并且还提供了集合的添加方法。

因此,当使用 add 方法修改集合时,我必须触发 PropertyChangeEventPropertyChangeEvent 有一个旧值和一个新值。

你如何处理旧值?

为了方便起见,我将在这里使用 String 的集合。例如

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);
          }
      }
}

获取旧值的一种方法可能是在添加之前创建一个副本

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);
    }
}

但在很多情况下,旧值可能会被白白复制。

所以另一个想法是不使用 add 方法,而是在

之前使用 contains
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);
}

这适用于 Set。但是当 names 集合是 ArrayList 时它将不起作用,因为 ArrayList 可以包含相同对象的多个实例。所以 contains 会 return 为真,但是 add 也会 return true.

在多线程环境中,首先通过包含检查然后添加也可能是一个问题,因为与此同时另一个线程可能已经添加了相同的对象。但我不想在这里介绍这种复杂性。我只是想为单线程环境找到一个好的设计,通常在UI(Event-Dispatch-Thread)中使用此类bean时。

在这种情况下,您如何处理旧值?

可以使用Map.putIfAbsent实现,键值相同。

如果密钥存在,将返回之前的(旧)值,并用于触发 firePropertyChange。 这在多线程环境中运行良好,只有一个线程能够添加一个新条目。