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 }