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</code> 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 * @since 3.0 038 */ 039public class EntrySetMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> { 040 041 private final Map<K, V> map; 042 private Iterator<Map.Entry<K, V>> iterator; 043 private Map.Entry<K, V> last; 044 private boolean canRemove = false; 045 046 /** 047 * Constructor. 048 * 049 * @param map the map to iterate over 050 */ 051 public EntrySetMapIterator(final Map<K, V> map) { 052 super(); 053 this.map = map; 054 this.iterator = map.entrySet().iterator(); 055 } 056 057 //----------------------------------------------------------------------- 058 /** 059 * Checks to see if there are more entries still to be iterated. 060 * 061 * @return <code>true</code> if the iterator has more elements 062 */ 063 @Override 064 public boolean hasNext() { 065 return iterator.hasNext(); 066 } 067 068 /** 069 * Gets the next <em>key</em> from the <code>Map</code>. 070 * 071 * @return the next key in the iteration 072 * @throws java.util.NoSuchElementException if the iteration is finished 073 */ 074 @Override 075 public K next() { 076 last = iterator.next(); 077 canRemove = true; 078 return last.getKey(); 079 } 080 081 //----------------------------------------------------------------------- 082 /** 083 * Removes the last returned key from the underlying <code>Map</code>. 084 * <p> 085 * This method can be called once per call to <code>next()</code>. 086 * 087 * @throws UnsupportedOperationException if remove is not supported by the map 088 * @throws IllegalStateException if <code>next()</code> has not yet been called 089 * @throws IllegalStateException if <code>remove()</code> has already been called 090 * since the last call to <code>next()</code> 091 */ 092 @Override 093 public void remove() { 094 if (canRemove == false) { 095 throw new IllegalStateException("Iterator remove() can only be called once after next()"); 096 } 097 iterator.remove(); 098 last = null; 099 canRemove = false; 100 } 101 102 //----------------------------------------------------------------------- 103 /** 104 * Gets the current key, which is the key returned by the last call 105 * to <code>next()</code>. 106 * 107 * @return the current key 108 * @throws IllegalStateException if <code>next()</code> has not yet been called 109 */ 110 @Override 111 public K getKey() { 112 if (last == null) { 113 throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()"); 114 } 115 return last.getKey(); 116 } 117 118 /** 119 * Gets the current value, which is the value associated with the last key 120 * returned by <code>next()</code>. 121 * 122 * @return the current value 123 * @throws IllegalStateException if <code>next()</code> has not yet been called 124 */ 125 @Override 126 public V getValue() { 127 if (last == null) { 128 throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()"); 129 } 130 return last.getValue(); 131 } 132 133 /** 134 * Sets the value associated with the current key. 135 * 136 * @param value the new value 137 * @return the previous value 138 * @throws UnsupportedOperationException if setValue is not supported by the map 139 * @throws IllegalStateException if <code>next()</code> has not yet been called 140 * @throws IllegalStateException if <code>remove()</code> has been called since the 141 * last call to <code>next()</code> 142 */ 143 @Override 144 public V setValue(final V value) { 145 if (last == null) { 146 throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()"); 147 } 148 return last.setValue(value); 149 } 150 151 //----------------------------------------------------------------------- 152 /** 153 * Resets the state of the iterator. 154 */ 155 @Override 156 public void reset() { 157 iterator = map.entrySet().iterator(); 158 last = null; 159 canRemove = false; 160 } 161 162 /** 163 * Gets the iterator as a String. 164 * 165 * @return a string version of the iterator 166 */ 167 @Override 168 public String toString() { 169 if (last != null) { 170 return "MapIterator[" + getKey() + "=" + getValue() + "]"; 171 } 172 return "MapIterator[]"; 173 } 174 175}