是否有一个带有Java侦听器的Map实现?

我想要一个Map实现,我可以在其中添加put()事件的监听器。

在标准或任何第三方库中有类似的东西吗?

我不知道任何标准或第三方,但它很容易,只需创建一个包装另一个Map并实现Map接口的类:

public class MapListener implements Map { private final Map delegatee; public MapListener(Map delegatee) { this.delegatee = delegatee; } // implement all Map methods, with callbacks you need. } 

品尝季节。 这是代表性的,而非规范性的。 当然它有问题。

 public class ListenerMap extends HashMap { public static final String PROP_PUT = "put"; private PropertyChangeSupport propertySupport; public ListenerMap() { super(); propertySupport = new PropertyChangeSupport(this); } public String getSampleProperty() { return sampleProperty; } @Override public Object put(Object k, Object v) { Object old = super.put(k, v); propertySupport.firePropertyChange(PROP_PUT, old, v); return old; } public void addPropertyChangeListener(PropertyChangeListener listener) { propertySupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertySupport.removePropertyChangeListener(listener); } } 

你基本上要求的是一个可以提供事件通知的缓存。 有一些产品,如Infinispan已经为您提供,但不知道您的用例很难推荐。

如果你想要一个简单的ObservableMap,它应该很容易实现。 您只需创建一个Observer模式。 你可以在这里找到一个例子。

这是一个地图的工作示例,它在put和remove上触发属性更改事件。 实施分为两类:

ListenerModel

包含与添加和删除更改侦听器相关的方法,以及触发属性更改的方法。

ListenerMap

扩展ListenerModel并通过委托实现java.util.Map接口。 它仅在put和remove方法中触发属性更改。 在其他方法上触发属性是有意义的,例如clear(),putAll()。

ListenerModel

 import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; public class ListenerModel { private final PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); public void addPropertyChangeListener(PropertyChangeListener listener) { changeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { changeSupport.removePropertyChangeListener(listener); } protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { changeSupport.firePropertyChange(propertyName, oldValue, newValue); } } 

ListenerMap

 import java.util.*; public class ListenerMap extends ListenerModel implements Map { public static final String PROP_PUT = "put"; public static final String REMOVE_PUT = "remove"; private Map delegate = new LinkedHashMap<>(); @Override public void clear() { delegate.clear(); } @Override public boolean containsKey(Object key) { return delegate.containsKey(key); } @Override public boolean containsValue(Object value) { return delegate.containsValue(value); } @Override public Set> entrySet() { return delegate.entrySet(); } @Override public V get(Object key) { return delegate.get(key); } @Override public boolean isEmpty() { return delegate.isEmpty(); } @Override public Set keySet() { return delegate.keySet(); } @Override public V put(K key, V value) { V oldValue = delegate.put(key, value); firePropertyChange(PROP_PUT, oldValue == null ? null : new AbstractMap.SimpleEntry<>(key, oldValue), new AbstractMap.SimpleEntry<>(key, value)); return oldValue; } @Override public void putAll(Map m) { delegate.putAll(m); } @Override public V remove(Object key) { V oldValue = delegate.remove(key); firePropertyChange(REMOVE_PUT, oldValue == null ? null : new AbstractMap.SimpleEntry<>(key, oldValue), null); return oldValue; } @Override public int size() { return delegate.size(); } @Override public Collection values() { return delegate.values(); } } 

这是一个JUnit 4测试:

 import org.junit.Before; import org.junit.Test; import java.beans.PropertyChangeListener; import java.util.Map; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; /** * Created by Gil on 01/07/2017. */ public class ListenerMapTest { private ListenerMap map; @Before public void setUp() throws Exception { map = new ListenerMap<>(); } @Test public void whenPut_ShouldFireTrigger() throws Exception { boolean[] fired = {false}; Map.Entry[] listenEntry = new Map.Entry[1]; boolean[] checkNull = {true}; PropertyChangeListener propertyChangeListener = evt -> { if (ListenerMap.PROP_PUT.equals(evt.getPropertyName())) { if(checkNull[0]) { assertThat(evt.getOldValue(), is(nullValue())); } else { Map.Entry oldValue = (Map.Entry) evt.getOldValue(); assertThat(oldValue.getKey(), is("k1")); assertThat(oldValue.getValue(), is("v1")); } listenEntry[0] = (Map.Entry) evt.getNewValue(); fired[0] = true; } }; map.addPropertyChangeListener(propertyChangeListener); map.put("k1", "v1"); assertThat(fired[0], is(true)); assertThat(listenEntry[0].getKey(), is("k1")); assertThat(listenEntry[0].getValue(), is("v1")); checkNull[0] = false; map.put("k1", "v2"); } @Test public void whenRemove_ShouldNotFire() throws Exception { boolean[] fired = {false}; PropertyChangeListener propertyChangeListener = evt -> { fired[0] = true; }; map.addPropertyChangeListener(propertyChangeListener); map.put("k1", "v1"); assertThat(fired[0], is(true)); fired[0] = false; map.removePropertyChangeListener(propertyChangeListener); map.put("k2", "v2"); assertThat(fired[0], is(false)); } }