diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.common')
-rw-r--r-- | bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/ListenerList.java | 80 |
1 files changed, 70 insertions, 10 deletions
diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/ListenerList.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/ListenerList.java index a746b742c..c62d79181 100644 --- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/ListenerList.java +++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/ListenerList.java @@ -10,6 +10,9 @@ *******************************************************************************/ package org.eclipse.core.runtime; +import java.util.Iterator; +import java.util.NoSuchElementException; + /** * This class is a thread safe list that is designed for storing lists of listeners. * The implementation is optimized for minimal memory footprint, frequent reads @@ -18,7 +21,7 @@ package org.eclipse.core.runtime; * to the underlying array data structure for reading, with the trust that they will * not modify the underlying array. * <p> - * <a name="same">A listener list handles the <i>same</i> listener being added + * <a name="same"></a>A listener list handles the <i>same</i> listener being added * multiple times, and tolerates removal of listeners that are the same as other * listeners in the list. For this purpose, listeners can be compared with each other * using either equality or identity, as specified in the list constructor. @@ -27,20 +30,27 @@ package org.eclipse.core.runtime; * Use the <code>getListeners</code> method when notifying listeners. The recommended * code sequence for notifying all registered listeners of say, * <code>FooListener.eventHappened</code>, is: - * + * </p> * <pre> - * Object[] listeners = myListenerList.getListeners(); - * for (int i = 0; i < listeners.length; ++i) { - * ((FooListener) listeners[i]).eventHappened(event); + * ListenerList<FooListener> fooListeners = new ListenerList<>(); + * //... + * for (FooListener listener : fooListeners) { + * listener.eventHappened(event); * } * </pre> - * - * </p><p> + * <p> + * Alternatively, you can call {@link #getListeners()} and then use a for-loop + * to iterate the {@code Object[]}. This might be insignificantly faster, but + * it lacks type-safety and risks inadvertent modifications to the array. + * </p> + * <p> * This class can be used without OSGi running. * </p> + * + * @param <E> the type of listeners in this list * @since org.eclipse.equinox.common 3.2 */ -public class ListenerList { +public class ListenerList<E> implements Iterable<E> { /** * The empty array singleton instance. @@ -96,7 +106,7 @@ public class ListenerList { * * @param listener the non-<code>null</code> listener to add */ - public synchronized void add(Object listener) { + public synchronized void add(E listener) { // This method is synchronized to protect against multiple threads adding // or removing listeners concurrently. This does not block concurrent readers. if (listener == null) @@ -124,7 +134,13 @@ public class ListenerList { * to the listener list during the notification will have no effect on * the notification itself. * <p> - * Note: Callers of this method <b>must not</b> modify the returned array. + * Note: Callers of this method <b>must not</b> modify the returned array. + * </p> + * <p> + * Note: The recommended and type-safe way to iterate this list is to use + * an enhanced 'for' statement, see {@link ListenerList}. + * This method is deprecated for new code. + * </p> * * @return the list of registered listeners */ @@ -133,6 +149,50 @@ public class ListenerList { } /** + * Returns an iterator over all the registered listeners. + * The resulting iterator is unaffected by subsequent adds or removes. + * Use this method when notifying listeners, so that any modifications + * to the listener list during the notification will have no effect on + * the notification itself. + * + * @return an iterator + * @since org.eclipse.equinox.common 3.8 + */ + @Override + public Iterator<E> iterator() { + return new ListenerListIterator<>(listeners); + } + + private static class ListenerListIterator<E> implements Iterator<E> { + private Object[] listeners; + private int i; + + public ListenerListIterator(Object[] listeners) { + this.listeners = listeners; + } + + @Override + public boolean hasNext() { + return i < listeners.length; + } + + @Override + public E next() { + if (i >= listeners.length) { + throw new NoSuchElementException(); + } + @SuppressWarnings("unchecked") // (E) is safe, because #add(E) only accepts Es + E next = (E) listeners[i++]; + return next; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + /** * Returns whether this listener list is empty. * * @return <code>true</code> if there are no registered listeners, and |