Is there a better way to have a listener on a java collection than wrap it in a class implementing the observer pattern ?
5 Answers
You should check out Glazed Lists
It contains observable List classes, which fire events whenever elements are added, removed, replaced, etc

- 22,624
- 6
- 36
- 37
-
Glazed Lists' TransformationList expects dispose() to be manually invoked instead of using WeakReferences for listeners....? 0.o There's got to be something better out there. – user515655 Nov 23 '14 at 20:09
You can using the ForwardingSet, ForwardingList, etc., from Guava to decorate a particular instance with the desired behavior.
Here's my own implementation that just uses plain JDK APIs:
// create an abstract class that implements this interface with blank implementations
// that way, annonymous subclasses can observe only the events they care about
public interface CollectionObserver<E> {
public void beforeAdd(E o);
public void afterAdd(E o);
// other events to be observed ...
}
// this method would go in a utility class
public static <E> Collection<E> observedCollection(
final Collection<E> collection, final CollectionObserver<E> observer) {
return new Collection<E>() {
public boolean add(final E o) {
observer.beforeAdd(o);
boolean result = collection.add(o);
observer.afterAdd(o);
return result;
}
// ... generate rest of delegate methods in Eclipse
};
}

- 1,761
- 1
- 16
- 13

- 14,093
- 16
- 59
- 76
"Commons-Events provides additional classes for firing and handling events. It focusses on the Java Collections Framework, providing decorators to other collections that fire events."

- 4,176
- 7
- 47
- 81

- 14,291
- 7
- 38
- 48
-
3Should be noted that this is still a sandbox project. An interesting one however. – BalusC Dec 21 '09 at 20:03
Well, if you don't actually need a java.util.Collection or List instance, you could use a DefaultListModel. I'm not aware of any "real" Collection implementations with builtin listener/observer support.

- 342,105
- 78
- 482
- 720
-
You linked the Java 6 version of DefaultListModel, which does not use Generics. The [Java 7 version](http://docs.oracle.com/javase/7/docs/api/javax/swing/DefaultListModel.html) does, which might make your suggestion more attractive. – Martin Rust Nov 15 '16 at 14:32
-
@MartinRust well, yeah, the answer is from 2 years before Java 7 came out. If I'm gonna update it I might as well use Java 8 now – Michael Borgwardt Nov 15 '16 at 15:02
there are many ways to achieve this - often i use this approach
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class ObservableArrayList<E> extends ArrayList<E> {
private @interface MethodId {
private static final int REMOVE = 2;
private static final int ADD = 1;
}
public interface ListObserver<E> {
void onElementAdded(E element);
void onElementRemoved(E element);
}
public ObservableArrayList(int capacity) {
super(capacity);
ensureObserver();
}
public ObservableArrayList() {
ensureObserver();
}
public ObservableArrayList(Collection<? extends E> collection) {
super(collection);
ensureObserver();
}
private List<WeakReference<ListObserver<E>>> _listObserverWeakRefList;
public void addObserver(ListObserver<E> observer) {
_listObserverWeakRefList.add(new WeakReference<ListObserver<E>> (observer));
}
private void ensureObserver() {
if (_listObserverWeakRefList == null) {
_listObserverWeakRefList = new ArrayList<>();
}
}
@Override
public boolean add(E object) {
super.add(object);
callObservable(MethodId.ADD, object);
return true;
}
@Override
public boolean remove(Object object) {
boolean removed = super.remove(object);
if (removed) callObservable(MethodId.REMOVE, object);
return removed;
}
private void callObservable(@MethodId int methodId, Object element) {
for (WeakReference<ListObserver<E>> observerRef : _listObserverWeakRefList) {
ListObserver<E> observer = observerRef.get();
if (observer != null) {
switch (methodId) {
case MethodId.ADD:
observer.onElementAdded((E) element);
break;
case MethodId.REMOVE:
observer.onElementRemoved((E) element);
break;
}
}
}
}
}

- 7,326
- 3
- 36
- 43