For the sake of completeness...
Say that you really do want to treat the Map
values as List
s, but you want to avoid copying the Set
into a List
each time.
For instance, maybe you are calling one library function that creates a Set
, but you are passing your Map<String, List<String>>
result to a (poorly-designed but out of your hands) library function that only takes Map<String, List<String>>
, even though somehow you know that the operations it does with the List
s are equally applicable to any Collection
(and thus any Set
). And for some reason you need to avoid the speed/memory overhead of copying each Set to a List.
In this super niche case, depending on the (maybe unknowable) behavior the library function needs out of your List
s, you may be able to create a List
view over each Set. Note that this is inherently unsafe (because the library function's requirements from each List
could presumably change without you knowing), so another solution should be preferred. But here's how you'd do it.
You'd create a class that implements the List
interface, takes a Set
in the constructor and assigns that Set to a field, and then uses that internal Set
to implement the List
API (to the extent possible, and desired).
Note that some List behavior you simply will not be able to imitate without storing the elements as a List
, and some behavior you will only partially be able to imitate. Again, this class is not a safe drop-in replacement for List
s in general. In particular, if you know that the use case requires index-related operations or MUTATING the List
, this approach would go south very fast.
public class ListViewOfSet<U> implements List<U> {
private final Set<U> wrappedSet;
public ListViewOfSet(Set<U> setToWrap) { this.wrappedSet = setToWrap; }
@Override public int size() { return this.wrappedSet.size(); }
@Override public boolean isEmpty() { return this.wrappedSet.isEmpty(); }
@Override public boolean contains(Object o) { return this.wrappedSet.contains(o); }
@Override public java.util.Iterator<U> iterator() { return this.wrappedSet.iterator(); }
@Override public Object[] toArray() { return this.wrappedSet.toArray(); }
@Override public <T> T[] toArray(T[] ts) { return this.wrappedSet.toArray(ts); }
@Override public boolean add(U e) { return this.wrappedSet.add(e); }
@Override public boolean remove(Object o) { return this.wrappedSet.remove(o); }
@Override public boolean containsAll(Collection<?> clctn) { return this.wrappedSet.containsAll(clctn); }
@Override public boolean addAll(Collection<? extends U> clctn) { return this.wrappedSet.addAll(clctn); }
@Override public boolean addAll(int i, Collection<? extends U> clctn) { throw new UnsupportedOperationException(); }
@Override public boolean removeAll(Collection<?> clctn) { return this.wrappedSet.removeAll(clctn); }
@Override public boolean retainAll(Collection<?> clctn) { return this.wrappedSet.retainAll(clctn); }
@Override public void clear() { this.wrappedSet.clear(); }
@Override public U get(int i) { throw new UnsupportedOperationException(); }
@Override public U set(int i, U e) { throw new UnsupportedOperationException(); }
@Override public void add(int i, U e) { throw new UnsupportedOperationException(); }
@Override public U remove(int i) { throw new UnsupportedOperationException(); }
@Override public int indexOf(Object o) { throw new UnsupportedOperationException(); }
@Override public int lastIndexOf(Object o) { throw new UnsupportedOperationException(); }
@Override public ListIterator<U> listIterator() { throw new UnsupportedOperationException(); }
@Override public ListIterator<U> listIterator(int i) { throw new UnsupportedOperationException(); }
@Override public List<U> subList(int i, int i1) { throw new UnsupportedOperationException(); }
}
...
Set<String> set = getSet(...);
ListViewOfSet<String> listOfNames = new ListViewOfSet<>(set);
...