A project im working on currently requires me to ensure that while looping through a map’s entries, if Entry.setValue is called, it would trigger a value change event. I see I can try something like adding a listener into an extension of the Map class on the .put method. My question is, would entries being changed trigger a listener in the map’s put method? Or would I be forced to extend the Map.Entry class and stick listener logic into its setValue method?
Apologies in advance if this question is dumb – im new to using Maps in this way and a lot of the information ive seen so far has only lead to extending the Map itself, which seems easiest but i dont know if it would cover my case.
Advertisement
Answer
In a pinch you could use the PropertyChangeSupport
class. It makes managing propertyChanges
very easy. There’s not much to tell here. The parties that want to listen for changes register their listener with the map. Then when the map modifies the value, the support fires off an event to all the listeners. The values that are returned in the Event class may be altered to ones chosing.
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.HashMap; public class PropertyChangeDemo implements PropertyChangeListener { public static void main(String[] args) { // leave static context of main new PropertyChangeDemo().start(); } public void start() { MyMap<String,Integer> map = new MyMap<>(); map.addMapListener(this); map.put("B",20); map.put("B",99); map.put("A",44); map.entrySet().forEach(System.out::println); }
Prints
source = map oldValue = null newValue = 20 source = map oldValue = 20 newValue = 99 source = map oldValue = null newValue = 44 A=44 B=99
A listener for demonstration.
public void propertyChange(PropertyChangeEvent pce) { System.out.println("source = " + pce.getPropertyName()); System.out.println("oldValue = " + pce.getOldValue()); System.out.println("newValue = " + pce.getNewValue()); } }
The modified class
class MyMap<K,V> extends HashMap<K,V> { private PropertyChangeSupport ps = new PropertyChangeSupport(this); // method to add listener public void addMapListener(PropertyChangeListener pcl) { ps.addPropertyChangeListener(pcl); } @Override public V put(K key, V value) { V ret = super.put(key,value); ps.firePropertyChange("map", ret, value); return ret; } }
Note: There may be issues that have been missed in this simple solution. Testing should be conducted before put into production use. For one, there are many different ways to set an Entry's
value. This only does it when put
is invoked, either by the user or indirectly by the map itself.