1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections4.iterators;
18
19 import java.util.Iterator;
20 import java.util.Map;
21
22 import org.apache.commons.collections4.MapIterator;
23 import org.apache.commons.collections4.ResettableIterator;
24
25 /**
26 * Implements a {@code MapIterator} using a Map entrySet.
27 * Reverse iteration is not supported.
28 * <pre>
29 * MapIterator it = map.mapIterator();
30 * while (it.hasNext()) {
31 * Object key = it.next();
32 * Object value = it.getValue();
33 * it.setValue(newValue);
34 * }
35 * </pre>
36 *
37 * @param <K> the type of keys
38 * @param <V> the type of mapped values
39 * @since 3.0
40 */
41 public class EntrySetMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> {
42
43 private final Map<K, V> map;
44 private Iterator<Map.Entry<K, V>> iterator;
45 private Map.Entry<K, V> last;
46 private boolean canRemove;
47
48 /**
49 * Constructs a new instance.
50 *
51 * @param map the map to iterate over
52 */
53 public EntrySetMapIterator(final Map<K, V> map) {
54 this.map = map;
55 this.iterator = map.entrySet().iterator();
56 }
57
58 /**
59 * Gets the current key, which is the key returned by the last call
60 * to {@code next()}.
61 *
62 * @return the current key
63 * @throws IllegalStateException if {@code next()} has not yet been called
64 */
65 @Override
66 public K getKey() {
67 if (last == null) {
68 throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()");
69 }
70 return last.getKey();
71 }
72
73 /**
74 * Gets the current value, which is the value associated with the last key
75 * returned by {@code next()}.
76 *
77 * @return the current value
78 * @throws IllegalStateException if {@code next()} has not yet been called
79 */
80 @Override
81 public V getValue() {
82 if (last == null) {
83 throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()");
84 }
85 return last.getValue();
86 }
87
88 /**
89 * Checks to see if there are more entries still to be iterated.
90 *
91 * @return {@code true} if the iterator has more elements
92 */
93 @Override
94 public boolean hasNext() {
95 return iterator.hasNext();
96 }
97
98 /**
99 * Gets the next <em>key</em> from the {@code Map}.
100 *
101 * @return the next key in the iteration
102 * @throws java.util.NoSuchElementException if the iteration is finished
103 */
104 @Override
105 public K next() {
106 last = iterator.next();
107 canRemove = true;
108 return last.getKey();
109 }
110
111 /**
112 * Removes the last returned key from the underlying {@code Map}.
113 * <p>
114 * This method can be called once per call to {@code next()}.
115 *
116 * @throws UnsupportedOperationException if remove is not supported by the map
117 * @throws IllegalStateException if {@code next()} has not yet been called
118 * @throws IllegalStateException if {@code remove()} has already been called
119 * since the last call to {@code next()}
120 */
121 @Override
122 public void remove() {
123 if (!canRemove) {
124 throw new IllegalStateException("Iterator remove() can only be called once after next()");
125 }
126 iterator.remove();
127 last = null;
128 canRemove = false;
129 }
130
131 /**
132 * Resets the state of the iterator.
133 */
134 @Override
135 public void reset() {
136 iterator = map.entrySet().iterator();
137 last = null;
138 canRemove = false;
139 }
140
141 /**
142 * Sets the value associated with the current key.
143 *
144 * @param value the new value
145 * @return the previous value
146 * @throws UnsupportedOperationException if setValue is not supported by the map
147 * @throws IllegalStateException if {@code next()} has not yet been called
148 * @throws IllegalStateException if {@code remove()} has been called since the
149 * last call to {@code next()}
150 */
151 @Override
152 public V setValue(final V value) {
153 if (last == null) {
154 throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()");
155 }
156 return last.setValue(value);
157 }
158
159 /**
160 * Gets the iterator as a String.
161 *
162 * @return a string version of the iterator
163 */
164 @Override
165 public String toString() {
166 if (last != null) {
167 return "MapIterator[" + getKey() + "=" + getValue() + "]";
168 }
169 return "MapIterator[]";
170 }
171
172 }