Map<Integer, String> map = new TreeMap<>();
map.put(1, "String1");
map.put(2, "String2");
map.put(3, "String3");
I wanted to convert the map's values to set. I know I could easily do
Set<String> set = new HashSet<>(map.values());
While thinking about this, I was curious what is map.values() by itself anyway? So I tried this
System.out.println("Set:"+ (map.values() instanceof Set));
System.out.println("List:"+ (map.values() instanceof List));
System.out.println("Queue:"+ (map.values() instanceof Queue));
System.out.println("SortedSet:"+ (map.values() instanceof SortedSet));
And the output surprisingly was
Set:false
List:false
Queue:false
SortedSet:false
This is all the documentation says.
a collection view of the values contained in this map
I then looked at the decompiled class file.
public Collection<V> values() {
if (values == null) {
values = new AbstractCollection<V>() {
public Iterator<V> iterator() {
return new Iterator<V>() {
private Iterator<Entry<K,V>> i = entrySet().iterator();
public boolean hasNext() {
return i.hasNext();
}
public V next() {
return i.next().getValue();
}
public void remove() {
i.remove();
}
};
}
public int size() {
return AbstractMap.this.size();
}
public boolean isEmpty() {
return AbstractMap.this.isEmpty();
}
public void clear() {
AbstractMap.this.clear();
}
public boolean contains(Object v) {
return AbstractMap.this.containsValue(v);
}
};
}
return values;
}
Why does java return an abstract implementation instead of List/Set/Queue which could be immediately compatible with use cases?
I don't know which Java version you are using, but I don't see an abstract class instance returned by values(). It returns an instance of TreeMap.Values, which is a class that extends AbstractCollection.
As to why it doesn't return a Set - that's simply due to the fact that the collection of values may contain duplicates, which a Set doesn't allow.
A List is also not ideal, since it would imply the values are ordered, which is not true for all Map implementations (such as HashMap).
BTW, instead of printing things like map.values() instanceof Set, you could have simply printed map.value().getClass().getName() to see the actual implementation class.
One reasons just from looking at the implementation: contains and iterator both look at the current contents of the map as opposed to the contents of the map when values() was called.
If you call values() and then change something in the map that change will be reflected in the Collection originally returned from values().
Map<String, String> map = new HashMap<String, String>();
map.put("some", "thing");
Collection<String> values = map.values();
System.out.println(values.size()); // 1
map.put("foo", "bar");
System.out.println(values.size()); // 2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With