001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.iterators; 018 019import java.util.Iterator; 020import java.util.Map; 021 022import org.apache.commons.collections4.MapIterator; 023import org.apache.commons.collections4.ResettableIterator; 024 025/** 026 * Implements a {@code MapIterator} using a Map entrySet. 027 * Reverse iteration is not supported. 028 * <pre> 029 * MapIterator it = map.mapIterator(); 030 * while (it.hasNext()) { 031 * Object key = it.next(); 032 * Object value = it.getValue(); 033 * it.setValue(newValue); 034 * } 035 * </pre> 036 * 037 * @param <K> the type of keys 038 * @param <V> the type of mapped values 039 * @since 3.0 040 */ 041public class EntrySetMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> { 042 043 private final Map<K, V> map; 044 private Iterator<Map.Entry<K, V>> iterator; 045 private Map.Entry<K, V> last; 046 private boolean canRemove; 047 048 /** 049 * Constructs a new instance. 050 * 051 * @param map the map to iterate over 052 */ 053 public EntrySetMapIterator(final Map<K, V> map) { 054 this.map = map; 055 this.iterator = map.entrySet().iterator(); 056 } 057 058 /** 059 * Gets the current key, which is the key returned by the last call 060 * to {@code next()}. 061 * 062 * @return the current key 063 * @throws IllegalStateException if {@code next()} has not yet been called 064 */ 065 @Override 066 public K getKey() { 067 if (last == null) { 068 throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()"); 069 } 070 return last.getKey(); 071 } 072 073 /** 074 * Gets the current value, which is the value associated with the last key 075 * returned by {@code next()}. 076 * 077 * @return the current value 078 * @throws IllegalStateException if {@code next()} has not yet been called 079 */ 080 @Override 081 public V getValue() { 082 if (last == null) { 083 throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()"); 084 } 085 return last.getValue(); 086 } 087 088 /** 089 * Checks to see if there are more entries still to be iterated. 090 * 091 * @return {@code true} if the iterator has more elements 092 */ 093 @Override 094 public boolean hasNext() { 095 return iterator.hasNext(); 096 } 097 098 /** 099 * 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}