diff options
author | Eike Stepper | 2008-01-18 19:01:05 +0000 |
---|---|---|
committer | Eike Stepper | 2008-01-18 19:01:05 +0000 |
commit | e96b6045e0276d25b92e55a26708ee339a8f1ecf (patch) | |
tree | 521f9545d93318cda31a80a04b85bceaeb07485b | |
parent | 08be45f1841f8b4cd798e90518d4dc8d6a67b12c (diff) | |
download | cdo-e96b6045e0276d25b92e55a26708ee339a8f1ecf.tar.gz cdo-e96b6045e0276d25b92e55a26708ee339a8f1ecf.tar.xz cdo-e96b6045e0276d25b92e55a26708ee339a8f1ecf.zip |
[215688] Create save points
https://bugs.eclipse.org/bugs/show_bug.cgi?id=215688
3 files changed, 1039 insertions, 5 deletions
diff --git a/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/MultiMapTest.java b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/MultiMapTest.java new file mode 100644 index 0000000000..5c650ab6b6 --- /dev/null +++ b/plugins/org.eclipse.net4j.tests/src/org/eclipse/net4j/util/tests/MultiMapTest.java @@ -0,0 +1,291 @@ +/*************************************************************************** + * Copyright (c) 2004 - 2008 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.tests; + +import org.eclipse.net4j.util.collection.MapEntry; +import org.eclipse.net4j.util.collection.MultiMap.ListBased; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author Eike Stepper + */ +public class MultiMapTest extends AbstractOMTest +{ + public void testListBased() throws Exception + { + ListBased<Integer, String> multiMap = new ListBased<Integer, String>(); + assertEquals(true, multiMap.isEmpty()); + assertEquals(0, multiMap.size()); + assertEquals(false, multiMap.containsKey(1)); + assertEquals(false, multiMap.containsValue("value" + 1)); + assertEquals(null, multiMap.get(1)); + + addDelegate(multiMap, 0, 0); + assertEquals(true, multiMap.isEmpty()); + assertEquals(0, multiMap.size()); + assertEquals(false, multiMap.containsKey(1)); + assertEquals(false, multiMap.containsValue("value" + 1)); + assertEquals(null, multiMap.get(1)); + + addDelegate(multiMap, 1, 10); + addDelegate(multiMap, 11, 10); + addDelegate(multiMap, 21, 10); + assertEquals(false, multiMap.isEmpty()); + assertEquals(30, multiMap.size()); + assertEquals(true, multiMap.containsKey(1)); + assertEquals(true, multiMap.containsValue("value" + 1)); + assertEquals("value" + 1, multiMap.get(1)); + assertEquals("value" + 6, multiMap.get(6)); + + addDelegate(multiMap, 6, 10); + assertEquals(false, multiMap.isEmpty()); + assertEquals(30, multiMap.size()); + assertEquals(true, multiMap.containsKey(1)); + assertEquals(true, multiMap.containsValue("value" + 1)); + assertEquals("value" + 1, multiMap.get(1)); + assertEquals("value" + 6, multiMap.get(6)); + assertEquals(null, multiMap.get(35)); + + addDelegate(multiMap, 26, 10); + assertEquals(false, multiMap.isEmpty()); + assertEquals(35, multiMap.size()); + assertEquals(true, multiMap.containsKey(1)); + assertEquals(true, multiMap.containsValue("value" + 1)); + assertEquals("value" + 1, multiMap.get(1)); + assertEquals("value" + 6, multiMap.get(6)); + assertEquals("value" + 35, multiMap.get(35)); + } + + public void testEntrySet() throws Exception + { + ListBased<Integer, String> multiMap = new ListBased<Integer, String>(); + assertEquals(true, multiMap.entrySet().isEmpty()); + assertEquals(0, multiMap.entrySet().size()); + assertEquals(false, multiMap.entrySet().contains(new MapEntry<Integer, String>(1, "value1"))); + + addDelegate(multiMap, 0, 0); + assertEquals(true, multiMap.entrySet().isEmpty()); + assertEquals(0, multiMap.entrySet().size()); + assertEquals(false, multiMap.entrySet().contains(new MapEntry<Integer, String>(1, "value1"))); + + addDelegate(multiMap, 1, 10); + addDelegate(multiMap, 11, 10); + addDelegate(multiMap, 21, 10); + assertEquals(false, multiMap.entrySet().isEmpty()); + assertEquals(30, multiMap.entrySet().size()); + assertEquals(true, multiMap.entrySet().contains(new MapEntry<Integer, String>(1, "value1"))); + + addDelegate(multiMap, 6, 10); + assertEquals(false, multiMap.entrySet().isEmpty()); + assertEquals(30, multiMap.entrySet().size()); + assertEquals(true, multiMap.entrySet().contains(new MapEntry<Integer, String>(1, "value1"))); + assertEquals(false, multiMap.entrySet().contains(new MapEntry<Integer, String>(35, "value35"))); + + addDelegate(multiMap, 26, 10); + assertEquals(false, multiMap.entrySet().isEmpty()); + assertEquals(35, multiMap.entrySet().size()); + assertEquals(true, multiMap.entrySet().contains(new MapEntry<Integer, String>(1, "value1"))); + assertEquals(true, multiMap.entrySet().contains(new MapEntry<Integer, String>(35, "value35"))); + } + + public void testKeySet() throws Exception + { + ListBased<Integer, String> multiMap = new ListBased<Integer, String>(); + assertEquals(true, multiMap.keySet().isEmpty()); + assertEquals(0, multiMap.keySet().size()); + assertEquals(false, multiMap.keySet().contains(1)); + + addDelegate(multiMap, 0, 0); + assertEquals(true, multiMap.keySet().isEmpty()); + assertEquals(0, multiMap.keySet().size()); + assertEquals(false, multiMap.keySet().contains(1)); + + addDelegate(multiMap, 1, 10); + addDelegate(multiMap, 11, 10); + addDelegate(multiMap, 21, 10); + assertEquals(false, multiMap.keySet().isEmpty()); + assertEquals(30, multiMap.keySet().size()); + assertEquals(true, multiMap.keySet().contains(1)); + + addDelegate(multiMap, 6, 10); + assertEquals(false, multiMap.keySet().isEmpty()); + assertEquals(30, multiMap.keySet().size()); + assertEquals(true, multiMap.keySet().contains(1)); + assertEquals(false, multiMap.keySet().contains(35)); + + addDelegate(multiMap, 26, 10); + assertEquals(false, multiMap.keySet().isEmpty()); + assertEquals(35, multiMap.keySet().size()); + assertEquals(true, multiMap.keySet().contains(1)); + assertEquals(true, multiMap.keySet().contains(35)); + } + + public void testValues() throws Exception + { + ListBased<Integer, String> multiMap = new ListBased<Integer, String>(); + assertEquals(true, multiMap.values().isEmpty()); + assertEquals(0, multiMap.values().size()); + assertEquals(false, multiMap.values().contains("value1")); + + addDelegate(multiMap, 0, 0); + assertEquals(true, multiMap.values().isEmpty()); + assertEquals(0, multiMap.values().size()); + assertEquals(false, multiMap.values().contains("value1")); + + addDelegate(multiMap, 1, 10); + addDelegate(multiMap, 11, 10); + addDelegate(multiMap, 21, 10); + assertEquals(false, multiMap.values().isEmpty()); + assertEquals(30, multiMap.values().size()); + assertEquals(true, multiMap.values().contains("value1")); + + addDelegate(multiMap, 6, 10); + assertEquals(false, multiMap.values().isEmpty()); + assertEquals(30, multiMap.values().size()); + assertEquals(true, multiMap.values().contains("value1")); + assertEquals(false, multiMap.values().contains("value35")); + + addDelegate(multiMap, 26, 10); + assertEquals(false, multiMap.values().isEmpty()); + assertEquals(35, multiMap.values().size()); + assertEquals(true, multiMap.values().contains("value1")); + assertEquals(true, multiMap.values().contains("value35")); + } + + public void testEntrySetIterator() throws Exception + { + ListBased<Integer, String> multiMap = new ListBased<Integer, String>(); + assertIterator(new HashSet<Object>(), multiMap.entrySet()); + + addDelegate(multiMap, 0, 0); + assertIterator(new HashSet<Object>(), multiMap.entrySet()); + + addDelegate(multiMap, 1, 10); + addDelegate(multiMap, 11, 10); + addDelegate(multiMap, 21, 10); + assertIterator(createMapEntries(1, 30), multiMap.entrySet()); + + addDelegate(multiMap, 6, 10); + assertIterator(createMapEntries(1, 30), multiMap.entrySet()); + + addDelegate(multiMap, 26, 10); + assertIterator(createMapEntries(1, 35), multiMap.entrySet()); + } + + public void testKeySetIterator() throws Exception + { + ListBased<Integer, String> multiMap = new ListBased<Integer, String>(); + assertIterator(new HashSet<Object>(), multiMap.keySet()); + + addDelegate(multiMap, 0, 0); + assertIterator(new HashSet<Object>(), multiMap.keySet()); + + addDelegate(multiMap, 1, 10); + addDelegate(multiMap, 11, 10); + addDelegate(multiMap, 21, 10); + assertIterator(createKeys(1, 30), multiMap.keySet()); + + addDelegate(multiMap, 6, 10); + assertIterator(createKeys(1, 30), multiMap.keySet()); + + addDelegate(multiMap, 26, 10); + assertIterator(createKeys(1, 35), multiMap.keySet()); + } + + public void testValuesIterator() throws Exception + { + ListBased<Integer, String> multiMap = new ListBased<Integer, String>(); + assertIterator(new HashSet<Object>(), multiMap.values()); + + addDelegate(multiMap, 0, 0); + assertIterator(new HashSet<Object>(), multiMap.values()); + + addDelegate(multiMap, 1, 10); + addDelegate(multiMap, 11, 10); + addDelegate(multiMap, 21, 10); + assertIterator(createValues(1, 30), multiMap.values()); + + addDelegate(multiMap, 6, 10); + assertIterator(createValues(1, 30), multiMap.values()); + + addDelegate(multiMap, 26, 10); + assertIterator(createValues(1, 35), multiMap.values()); + } + + private void addDelegate(ListBased<Integer, String> multiMap, int start, int count) + { + Map<Integer, String> map = new HashMap<Integer, String>(); + for (int i = 0; i < count; i++) + { + int key = start + i; + map.put(key, "value" + key); + } + + multiMap.getDelegates().add(map); + } + + private void assertIterator(Set<?> expectedObjects, Collection<?> actualObjects) + { + for (Object actualObject : actualObjects) + { + if (!expectedObjects.remove(actualObject)) + { + fail("Unexpected object: " + actualObject); + } + } + + if (!expectedObjects.isEmpty()) + { + fail("Missing objects: " + expectedObjects); + } + } + + private Set<Object> createMapEntries(int start, int count) + { + Set<Object> result = new HashSet<Object>(); + for (int i = 0; i < count; i++) + { + int key = start + i; + result.add(new MapEntry<Integer, String>(key, "value" + key)); + } + + return result; + } + + private Set<Object> createKeys(int start, int count) + { + Set<Object> result = new HashSet<Object>(); + for (int i = 0; i < count; i++) + { + int key = start + i; + result.add(key); + } + + return result; + } + + private Set<Object> createValues(int start, int count) + { + Set<Object> result = new HashSet<Object>(); + for (int i = 0; i < count; i++) + { + int key = start + i; + result.add("value" + key); + } + + return result; + } +} diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/container/delegate/ContainerMap.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/container/delegate/ContainerMap.java index c6f51559e2..ea033de411 100644 --- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/container/delegate/ContainerMap.java +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/internal/util/container/delegate/ContainerMap.java @@ -19,7 +19,6 @@ import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; -import java.util.Map.Entry; /** * @author Eike Stepper @@ -62,7 +61,7 @@ public class ContainerMap<K, V> extends AbstractDelegator<Map.Entry<K, V>> imple { event.addDelta(new ContainerMapEntry<K, V>(key, removed), IContainerDelta.Kind.REMOVED); } - + event.addDelta(new ContainerMapEntry<K, V>(key, value), IContainerDelta.Kind.ADDED); fireEvent(event); return removed; @@ -85,10 +84,10 @@ public class ContainerMap<K, V> extends AbstractDelegator<Map.Entry<K, V>> imple { event.addDelta(new ContainerMapEntry<K, V>(key, removed), IContainerDelta.Kind.REMOVED); } - + event.addDelta(new ContainerMapEntry<K, V>(key, value), IContainerDelta.Kind.ADDED); } - + dispatchEvent(event); } @@ -102,7 +101,7 @@ public class ContainerMap<K, V> extends AbstractDelegator<Map.Entry<K, V>> imple { fireRemovedEvent(new ContainerMapEntry<Object, V>(key, removed)); } - + return removed; } diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/collection/MultiMap.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/collection/MultiMap.java new file mode 100644 index 0000000000..401ae5220f --- /dev/null +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/collection/MultiMap.java @@ -0,0 +1,744 @@ +/*************************************************************************** + * Copyright (c) 2004 - 2008 Eike Stepper, Germany. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.net4j.util.collection; + +import org.eclipse.net4j.util.ObjectUtil; + +import java.util.AbstractCollection; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * @author Eike Stepper + */ +public abstract class MultiMap<K, V> implements Map<K, V> +{ + private transient Entries entries; + + private transient Set<K> keys; + + private transient Collection<V> values; + + public MultiMap() + { + } + + public abstract int getDelegateCount(); + + public Map<K, V> getDelegate(int index) + { + if (0 <= index && index < getDelegateCount()) + { + return doGetDelegate(index); + } + + return null; + } + + /** + * @category WRITE + */ + public void clear() + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public V put(K key, V value) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public void putAll(Map<? extends K, ? extends V> t) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public V remove(Object key) + { + throw new UnsupportedOperationException(); + } + + /** + * @category READ + */ + public boolean containsKey(Object key) + { + return containsKey(key, getDelegateCount()); + } + + /** + * @category READ + */ + public boolean containsValue(Object value) + { + for (int i = 0; i < getDelegateCount(); i++) + { + Map<K, V> delegate = getDelegate(i); + if (delegate != null) + { + if (delegate.containsValue(value)) + { + return true; + } + } + } + + return false; + } + + /** + * @category READ + */ + public V get(Object key) + { + for (int i = 0; i < getDelegateCount(); i++) + { + Map<K, V> delegate = getDelegate(i); + if (delegate != null) + { + if (delegate.containsKey(key)) + { + return delegate.get(key); + } + } + } + + return null; + } + + /** + * @category READ + */ + public int size() + { + int size = 0; + Map<K, V> delegate = getDelegate(0); + if (delegate != null) + { + size += delegate.size(); + for (int i = 1; i < getDelegateCount(); i++) + { + delegate = getDelegate(i); + if (delegate != null) + { + Set<K> keySet = delegate.keySet(); + for (K key : keySet) + { + if (!containsKey(key, i)) + { + ++size; + } + } + } + } + } + + return size; + } + + /** + * @category READ + */ + public boolean isEmpty() + { + for (int i = 0; i < getDelegateCount(); i++) + { + Map<K, V> delegate = getDelegate(i); + if (delegate != null) + { + if (!delegate.isEmpty()) + { + return false; + } + } + } + + return true; + } + + public synchronized Set<Map.Entry<K, V>> entrySet() + { + if (entries == null) + { + entries = new Entries(); + } + + return entries; + } + + public synchronized Set<K> keySet() + { + if (keys == null) + { + keys = new Keys(); + } + + return keys; + } + + public synchronized Collection<V> values() + { + if (values == null) + { + values = new Values(); + } + + return values; + } + + protected boolean containsKey(Object key, int delegateCount) + { + for (int i = 0; i < delegateCount; i++) + { + Map<K, V> delegate = getDelegate(i); + if (delegate != null) + { + if (delegate.containsKey(key)) + { + return true; + } + } + } + + return false; + } + + protected abstract Map<K, V> doGetDelegate(int index); + + /** + * @author Eike Stepper + */ + public static class ListBased<K, V> extends MultiMap<K, V> + { + private List<Map<K, V>> delegates; + + public ListBased() + { + } + + public ListBased(List<Map<K, V>> delegates) + { + this.delegates = delegates; + } + + public List<Map<K, V>> getDelegates() + { + if (delegates == null) + { + delegates = createDelegates(); + } + + return delegates; + } + + public void setDelegates(List<Map<K, V>> delegates) + { + this.delegates = delegates; + } + + @Override + public int getDelegateCount() + { + return getDelegates().size(); + } + + @Override + protected Map<K, V> doGetDelegate(int index) + { + return getDelegates().get(index); + } + + protected List<Map<K, V>> createDelegates() + { + return new ArrayList<Map<K, V>>(); + } + } + + /** + * @author Eike Stepper + */ + private final class Entries extends AbstractSet<Entry<K, V>> + { + public Entries() + { + } + + /** + * @category WRITE + */ + public boolean add(Entry<K, V> o) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean addAll(Collection<? extends Entry<K, V>> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public void clear() + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean remove(Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean removeAll(Collection<?> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean retainAll(Collection<?> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category READ + */ + @SuppressWarnings("unchecked") + public boolean contains(Object o) + { + if (o instanceof Map.Entry) + { + for (int i = 0; i < getDelegateCount(); i++) + { + Map<K, V> delegate = getDelegate(i); + if (delegate != null) + { + K key = ((Map.Entry<K, V>)o).getKey(); + if (delegate.containsKey(key)) + { + V value = ((Map.Entry<K, V>)o).getValue(); + if (ObjectUtil.equals(delegate.get(key), value)) + { + return true; + } + } + } + } + } + + return false; + } + + /** + * @category READ + */ + public boolean isEmpty() + { + return MultiMap.this.isEmpty(); + } + + /** + * @category READ + */ + public int size() + { + return MultiMap.this.size(); + } + + public Iterator<Entry<K, V>> iterator() + { + return new Iterator<Entry<K, V>>() + { + private Entry<K, V> next; + + private int delegateIndex = -1; + + private Iterator<Entry<K, V>> delegateIt; + + /** + * @category WRITE + */ + public void remove() + { + throw new UnsupportedOperationException(); + } + + /** + * @category READ + */ + public boolean hasNext() + { + next = null; + while (next == null) + { + if (delegateIt == null) + { + Map<K, V> delegate = getDelegate(++delegateIndex); + if (delegate == null) + { + // All delegates have been iterated + break; + } + + delegateIt = delegate.entrySet().iterator(); + } + + if (delegateIt.hasNext()) + { + next = delegateIt.next(); + + // Check if this key has been returned previously + if (containsKey(next.getKey(), delegateIndex)) + { + next = null; + } + } + else + { + // Determine next delegate iterator in next loop + delegateIt = null; + } + } + + return next != null; + } + + /** + * @category READ + */ + public Map.Entry<K, V> next() + { + if (next == null) + { + throw new NoSuchElementException(); + } + + try + { + return next; + } + finally + { + next = null; + } + } + }; + } + } + + /** + * @author Eike Stepper + */ + private final class Keys extends AbstractSet<K> + { + public Keys() + { + } + + /** + * @category WRITE + */ + public boolean add(K o) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean addAll(Collection<? extends K> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public void clear() + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean remove(Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean removeAll(Collection<?> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean retainAll(Collection<?> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category READ + */ + public boolean contains(Object o) + { + return MultiMap.this.containsKey(o); + } + + /** + * @category READ + */ + public boolean isEmpty() + { + return MultiMap.this.isEmpty(); + } + + /** + * @category READ + */ + public int size() + { + return MultiMap.this.size(); + } + + /** + * @category READ + */ + public Iterator<K> iterator() + { + return new Iterator<K>() + { + private K next; + + private int delegateIndex = -1; + + private Iterator<K> delegateIt; + + /** + * @category WRITE + */ + public void remove() + { + throw new UnsupportedOperationException(); + } + + /** + * @category READ + */ + public boolean hasNext() + { + next = null; + while (next == null) + { + if (delegateIt == null) + { + Map<K, V> delegate = getDelegate(++delegateIndex); + if (delegate == null) + { + // All delegates have been iterated + break; + } + + delegateIt = delegate.keySet().iterator(); + } + + if (delegateIt.hasNext()) + { + next = delegateIt.next(); + + // Check if this key has been returned previously + if (containsKey(next, delegateIndex)) + { + next = null; + } + } + else + { + // Determine next delegate iterator in next loop + delegateIt = null; + } + } + + return next != null; + } + + /** + * @category READ + */ + public K next() + { + if (next == null) + { + throw new NoSuchElementException(); + } + + try + { + return next; + } + finally + { + next = null; + } + } + }; + } + } + + /** + * @author Eike Stepper + */ + private final class Values extends AbstractCollection<V> + { + public Values() + { + } + + /** + * @category WRITE + */ + public boolean add(V o) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean addAll(Collection<? extends V> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public void clear() + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean remove(Object o) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean removeAll(Collection<?> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category WRITE + */ + public boolean retainAll(Collection<?> c) + { + throw new UnsupportedOperationException(); + } + + /** + * @category READ + */ + public boolean contains(Object o) + { + return MultiMap.this.containsValue(o); + } + + /** + * @category READ + */ + public boolean isEmpty() + { + return MultiMap.this.isEmpty(); + } + + /** + * @category READ + */ + public int size() + { + return MultiMap.this.size(); + } + + /** + * @category READ + */ + public Iterator<V> iterator() + { + return new Iterator<V>() + { + private Iterator<Entry<K, V>> delegateIt = entrySet().iterator(); + + /** + * @category WRITE + */ + public void remove() + { + throw new UnsupportedOperationException(); + } + + /** + * @category READ + */ + public boolean hasNext() + { + return delegateIt.hasNext(); + } + + /** + * @category READ + */ + public V next() + { + return delegateIt.next().getValue(); + } + }; + } + } +} |