I am very new to java so sorry in advance if anything I say sounds newbish, be gentle.
I have implemented a basic Observer Pattern. Some observers should only listen to one update and then immediately remove themselves from the observers/listeners list. However, whenever I tried doing that I got the famous java.util.concurrentmodificationexception error.
I'm obviously getting this error because I'm changing the list while still iterating over it, yet I am still unsure what is the right solution. I'm wondering if I'm even doing this the right way. If I am, what would be the needed fix to make it work? And if I'm not, I'd like to get suggestions for a better way of achieving what I'm trying to do.
Here's my code:
public interface Listener {
public void onValueChange(double newValue);
}
public class Observed {
private int value;
List<Listener> listeners = new ArrayList<>();
public void addListener(Listener toAdd) {
listeners.add(toAdd);
}
public void removeListener(Listener toRemove) {
listeners.remove(toRemove);
}
public void changeValue(double newValue) {
value = newValue;
for (Listener l : listeners) l.onValueChange(newValue);
}
}
public class SomeClassA implements Listener{
private Observed observed;
SomeClassA(Observed observed) {
this.observed = observed;
}
@Override
public void onValueChange(double newValue) {
System.out.println(newValue);
observed.removeListener(this);
}
}
public class SomeClassB implements Listener{
@Override
public void onValueChange(double newValue) {
System.out.println(newValue);
}
}
public class ObserverTest {
public static void main(String[] args) {
Observed observed = new Observed();
SomeClassA objectA = new SomeClassA(observed);
SomeClassB objectB = new SomeClassB();
observed.addListener(objectB);
observed.addListener(objectA);
observed.changeValue(4);
}
}
one ways is to go fo CopyOnWriteArraylist instead of ArrayList .
CopyOnWriteArraylist is a thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.
Reason why its thrown in your case
you are modifying a collection directly while it is iterating over the collection under method changeValue()
You can not remove items from a collection while you are iterating over it. That is, unless you use the Iterator#remove method. Since that is not a possibility in this case, an alternative is make a copy of your listener list and iterate over that instead. In that case the original listener list is free to be manipulated by the individual listeners:
public void changeValue(double newValue) {
value = newValue;
List<Listener> copyOfListeners = new ArrayList<Listener>(listeners);
for(Listener l : copyOfListeners) {
l.onValueChange(newValue);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With