Если вы хотите, чтобы Map
автоматически обновлялся при изменении id
объекта OtherClass
, вам нужно написать код для этого самостоятельно.
Если только карта и объект тесно связан, вы должны сохранить логику c отделенной, например, путем отслеживания изменений свойств.
Я бы рекомендовал построить его вокруг класса PropertyChangeSupport
в Java Библиотека времени выполнения.
OtherClass
Сначала необходимо включить отслеживание изменений свойств.
Я добавил свойство name
, чтобы улучшить вывод тестового кода в конце этого ответа .
public final class OtherClass {
private final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private int id;
private String name;
public OtherClass(int id, String name) {
this.id = id;
this.name = name;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
public int getId() {
return this.id;
}
public void setId(int id) {
int oldId = this.id;
this.id = id;
this.pcs.firePropertyChange("id", oldId, id);
}
public String getName() {
return this.name;
}
public void setName(String name) {
String oldName = this.name;
this.name = name;
this.pcs.firePropertyChange("name", oldName, name);
}
@Override
public String toString() {
return "OtherClass[" + this.id + ", " + this.name + "]";
}
}
OtherMap
Далее необходимо инкапсулировать Map
, чтобы обработчик изменения свойства можно было правильно обработать.
Чтобы предотвратить утечки памяти, важно clear()
OtherMap
, когда он больше не нужен, в противном случае ссылка на один объект OtherMap
, находящийся в OtherMap
, сохранит карту и все объекты на карте живыми в памяти. Чтобы помочь с этим, я создал объект AutoCloseable
, чтобы его можно было использовать с оператором try-with-resources, а анализаторы кода помогли выделить необходимость закрыть / очистить карту.
final class OtherMap implements AutoCloseable {
private final PropertyChangeListener listener = this::onPropertyChange;
private Map<Integer, OtherClass> map = new HashMap<>();
public OtherMap() {
}
public Set<Integer> keys() {
return Collections.unmodifiableSet(this.map.keySet());
}
public Collection<OtherClass> values() {
return Collections.unmodifiableCollection(this.map.values());
}
public OtherClass get(int id) {
return this.map.get(id);
}
public OtherClass add(OtherClass other) {
OtherClass prev = this.map.put(other.getId(), other);
if (prev != null)
prev.removePropertyChangeListener(this.listener);
other.addPropertyChangeListener(this.listener);
return prev;
}
public OtherClass remove(int id) {
OtherClass other = this.map.remove(id);
if (other != null)
other.removePropertyChangeListener(this.listener);
return other;
}
public void clear() {
this.map.values().forEach(other -> other.removePropertyChangeListener(this.listener));
this.map.clear();
}
private void onPropertyChange(PropertyChangeEvent evt) {
if (! "id".equals(evt.getPropertyName()))
return;
Integer oldId = (Integer) evt.getOldValue();
Integer newId = (Integer) evt.getNewValue();
if (oldId.equals(newId))
return;
OtherClass other = (OtherClass) evt.getSource();
if (this.map.putIfAbsent(newId, other) != null)
throw new IllegalStateException("Duplicate key");
if (! this.map.remove(oldId, other)) {
this.map.remove(newId);
throw new IllegalStateException();
}
}
@Override
public String toString() {
return this.map.toString();
}
@Override
public void close() {
clear();
}
}
Тест
OtherClass eeny = new OtherClass(3, "Eeny");
OtherClass meeny = new OtherClass(5, "Meeny");
OtherClass miny = new OtherClass(7, "Miny");
OtherClass moe = new OtherClass(9, "Moe");
OtherMap otherMap = new OtherMap();
otherMap.add(eeny);
otherMap.add(meeny);
otherMap.add(miny);
otherMap.add(moe);
System.out.println("Before: " + otherMap);
meeny.setId(2);
otherMap.remove(miny.getId());
miny.setId(4);
System.out.println("After: " + otherMap);
Выход
Before: {3=OtherClass[3, Eeny], 5=OtherClass[5, Meeny], 7=OtherClass[7, Miny], 9=OtherClass[9, Moe]}
After: {2=OtherClass[2, Meeny], 3=OtherClass[3, Eeny], 9=OtherClass[9, Moe]}