This is one of the JavaIdioms
You want to use the new collections library and and iterators. But the collection is occasionally modified and you are worried about the
. In particular, suppose you have a collection which has three extant iterators. If you modify the
collection, the iterators will now throw a comodification exception (to let you know that the data you are iterating over has changed). Catching
this exception everywhere you use iterators is a pain
in the butt.
Notice that, frequently, it doesn't strongly affect program correctness if the existing iterators use a slightly out of date version of the collection.
Therefore, when making a change to the collection observers, replace it with a copy like so
public void addFrameListener(FrameListener foo)
_listenerList = new ArrayList(_listenerList);
Now, in the example scenario, the three iterators won't fail (because the collection they point to hasn't changed), but new iterators will iterate over
the updated collection. And, eventually, the old colleciton will be garbage collected (after all the iterators over it are garbage collected).
In addition, use java.util.unmodifiable...() methods to wrap your collections whenever you hand them out to som other part of the code that is not at all supposed to modify the collection (available since Java 1.2). In the example scenario, the three iterators should get unmodifiable versions (or one unmodifiable version) of the collection.
If you use such collections, you only need to make a copy when modifying the collection, rather than when iterating over it. This is more efficient if iteration is more common than modification, which is often the case in GUI components.
I began to use this for custom listeners in GUI code (using the 1.1 Event model). Recent conversations around the lab suggest it's a common trick
to avoid comodification exceptions.
Originally by WilliamGrosso
. Refactored with contributions from NatPryce
It should be noted that if you only copy when you modify as Nat suggests, you can absorb most of the cost of duplicating the collection -- which can be considerable. -- RobertDiFalco
Smalltalk has #copyWith:, which does the copy and append in a single step. It is optimised so that the copy allows room for the extra element. -- AnonymousDonor
If you assume that, given a writable copy you will at some point need to grow the underlying data-structure (such as for indexed collections), you will already be creating a copy. I'd like to explore the idea of doing this on a less granular basis. Something like toMutable
. I dunno. -- RobertDiFalco
Basically, you would want a CopyOnWrite
that would copy on the first modification for owner a
but not for the second or third modification. This is fairly easy to do with CeePlusPlus
because you can overload the assignment operators. In Java or SmallTalk
, it is difficult to determine the boundaries of ownership. I want to avoid having to perform #copyWith on each modification. -- RobertDiFalco
Does ownership matter? We can do an implicit toMutable
, and an implicit toImmutable
. We only need the copy when switching from immutable to mutable. Two adds
by different people can (and should) use the same growable collection, so ownership doesn't matter. -- AnonymousDonor
(Refactored slightly - please correct any misattributions etc and DeleteMe
This is a well-known Smalltalk idiom. I learned it and started teaching it
in the late 80's. It is described on page 261 of the DesignPatternsBook
, where it
is said to be "too expensive to do in general", which is true, but irrelevant,
since the special case of it not being too expensive happens 95% of the time. -RalphJohnson
True enough, I've also noticed that in some SmallTalk
enumerator implementations, they will create a copy and iterate over that if the enumerator does something that could change the order of elements -- like #removeSuchThat. i.e. make a copy, an enumerate over the copy but actually remove
the elements from self
. -- rad