How to create a custom iterator for a Map implementation?
I implemented a unique map. It's a hashmap which is bi-directional, where not only keys are unique but values too.
public interface UniqueMap<K,V>{
V uniquePut(K key, V value);
UniqueMap<V,K> inverse();
}
This is a possible implementation:
public class SimpleUniqueMap<K,V> implements UniqueMap<K,V>, Iterable<K>{
public HashMap<K,V> uniqueMap = new HashMap<K,V>();
class EnumSimpleUniqueMap implements Iterator<K>{
int count = uniqueMap.size();
public boolean hasNext(){
return count > 0;
}
public K next(){
if(count == 0){
throw new NoSuchElementException();
}else{
count--;
//...
}
}
public void remove(){
throw new UnsupportedOperationException();
}
}
public Iterator<V> iterator(){
return new EnumSimpleUniqueMap();
}
public V uniquePut(K key, V value){
return null;
}
public UniqueMap<V,K> inverse(){
return null;
}
}
As you can see I already tried to implement an iter开发者_Python百科ator for my unique map. But from a hashmap values are not accessed by position but by key. So usually I would take the counter and access values but in this case it is not possibe.
Actually it would be enough to iterate over the keys and retrieve them one by another. How can I do that? Is there a way to retrieve some kind of entry object containing both key and value?
I know that I can retrieve the iterator from an map object but this is not an option for me.
UPDATE: Most simple of all, use
org.apache.commons.collections.BidiMap
But if your really want to roll your own, then consider this:
Usually, Maps
don't implement Iterable
. In your case, you can get the Iterator
for free by calling any of these
map.keys().iterator(); // is the same as
map.inverse().values().iterator();
map.values().iterator(); // is the same as
map.inverse().keys().iterator();
map.entrySet().iterator(); // almost the same as
map.inverse().entrySet().iterator();
on your map, depending on what you want to iterate over. For that, you'd have to make
public interface UniqueMap<K,V> extends Map<K, V> {
// no need for uniquePut(), you already have Map.put()
UniqueMap<V,K> inverse();
}
It's also a good idea to make your implementation extend
java.util.AbstractMap<K, V>
Which has a lot of base functionality for maps already.
You could implement your iterator()
method by simply delegating to your backing hashmap's keyset iterator:
public Iterator<K> iterator(){
return uniqueMap.keySet().iterator();
}
Of course, as Lukas said, usually a map will not be iterable, but provide collection views which themselves are iterable.
Also, it might be a good idea for your unique map implementation to have HashMaps in both directions.
Also, think about (and specify it in the interface): What should happen if the user inserts a new key with an already existing value - does this fail, get ignored, remove the existing mapping, or what?
You should have a look to the Guava library (Google Collection). They have a BiMap implementation that seems to be exactly what your are trying to implement...
精彩评论