View Javadoc
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 }