Hi there,

I never really worked with weak references before. Now I created an ObserverList and used WeakReference to solve the Lapsed Observer problem.
However, I am not quite sure if I did it right. Unfortunately these kinds of classes are not that easy to test.
I would really appreciate some input from more experienced programmers on this.

As a backing List I use a CopyOnWriteArrayList. I also use a custom iterator to filter out lapsed observers.
Lapsed observers _should_ (if I implemented this correctly) be filtered out everytime the list is iterated over.
import java.lang.ref.WeakReference;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
 
public class CowalObsList<E> implements ObsList<E> {
 
	/**
	 * We use a copy on write array list to make out observer list thread safe and to protect us against ConcurrentModificationException's.
	 * 
	 * @see CopyOnWriteArrayList
	 * @see ConcurrentModificationException
	 */
	private final CopyOnWriteArrayList<WeakReference<E>> list = new CopyOnWriteArrayList<>();
 
	/**
	 * Adds the given observer to this observer list.<br>
	 * This method will not result in a ConcurrentModificationException even if an iteration is currently taking place.<br>
	 * The added observer will be included in the next iteration over this observer list.
	 * 
	 * @param obs
	 * 		the observer to be added
	 * @throws NullPointerException
	 * 		if obs is null
	 * @see ConcurrentModificationException
	 */
	public void addObserver(E obs) {
		if (obs == null) {
			throw new NullPointerException();
		}
		WeakReference<E> ref = new WeakReference<>(obs);
		list.add(ref);
	}
 
	/**
	 * Removes the observer from this observer list if it is contained.<br>
	 * This method will not result in a ConcurrentModificationException even if an iteration is currently taking place.<br>
	 * If the observer is not contained in this observer list this method does nothing.
	 * 
	 * @param obs
	 * 		the observer to be removed
	 * @throws NullPointerException
	 * 		if obs is null
	 * @see ConcurrentModificationException
	 */
	public void removeObserver(E obs) {
		if (obs == null) {
			throw new NullPointerException();
		}
		for (WeakReference<E> ref : list) {
			if (ref.get() == obs || ref.get() == null) {
				list.remove(ref);
			}
		}
	}
 
	/**
	 * Returns an iterator over the elements in this observer list in a non defined sequence.<br>
	 * The returned iterator provides a snapshot of the state of the list when the iterator was constructed.<br>
	 * No synchronization is needed while traversing the iterator. The iterator does NOT support the remove method.
	 * 
	 * @see CopyOnWriteArrayList#iterator()
	 */
	public Iterator<E> iterator() {
		return new CowalObsListIterator<>(this);
	}
 
	/**
	 * This custom Iterator is used to filter out lapsed observers from this observer list.<br>
	 * It also makes sure that the user does not have to deal with WeakReference's.
	 */
	private static class CowalObsListIterator<E> implements Iterator<E> {
 
		/**
		 * The CowalObserverList that created this iterator.
		 */
		final CowalObsList<E> cowalList;
		/**
		 * An iterator of the List that is backing the cowalList.
		 */
		final Iterator<WeakReference<E>> delegate;
		/**
		 * The next reference from which to return the referent in the {@link #next()} method. 
		 */
		WeakReference<E> next;
 
		public CowalObsListIterator(CowalObsList<E> source) {
			cowalList = source;
			delegate = cowalList.list.iterator();
			next = null;
		}
 
		public boolean hasNext() {
			// Filter out lapsed observers
			while (next == null && delegate.hasNext()) {
				WeakReference<E> ref = delegate.next();
				if (ref.get() == null) {
					// The reference is referring to a lapsed observer and must be removed from the backing list.
					cowalList.list.remove(ref);
				} else {
					// Breaks the loop.
					next = ref;
				}
			}
			return next != null;
		}
 
		public E next() {
			E element = next.get();
			// Important to set next to null after a call to the next() method!
			next = null;
			return element;
		}
 
	}
 
}

Thank you for your time.