The answer as well as other answers are correct. I am going to add to those answers with a solution that I think will be helpful. I think this comes up often in programming. One thing to note is that for Collections (Lists, Sets, etc.) the main issue is adding to the Collection. That is where things break down. Even removing is OK.
In most cases, we can use Collection<? extends T>
rather then Collection<T>
and that should be the first choice. However, I am finding cases where it is not easy to do that. It is up for debate as to whether that is always the best thing to do. I am presenting here a class DownCastCollection that can take convert a Collection<? extends T>
to a Collection<T>
(we can define similar classes for List, Set, NavigableSet,..) to be used when using the standard approach is very inconvenient. Below is an example of how to use it (we could also use Collection<? extends Object>
in this case, but I am keeping it simple to illustrate using DownCastCollection.
/**Could use Collection<? extends Object> and that is the better choice.
* But I am doing this to illustrate how to use DownCastCollection. **/
public static void print(Collection<Object> col){
for(Object obj : col){
System.out.println(obj);
}
}
public static void main(String[] args){
ArrayList<String> list = new ArrayList<>();
list.addAll(Arrays.asList("a","b","c"));
print(new DownCastCollection<Object>(list));
}
Now the class:
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class DownCastCollection<E> extends AbstractCollection<E> implements Collection<E> {
private Collection<? extends E> delegate;
public DownCastCollection(Collection<? extends E> delegate) {
super();
this.delegate = delegate;
}
@Override
public int size() {
return delegate ==null ? 0 : delegate.size();
}
@Override
public boolean isEmpty() {
return delegate==null || delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
if(isEmpty()) return false;
return delegate.contains(o);
}
private class MyIterator implements Iterator<E>{
Iterator<? extends E> delegateIterator;
protected MyIterator() {
super();
this.delegateIterator = delegate == null ? null :delegate.iterator();
}
@Override
public boolean hasNext() {
return delegateIterator != null && delegateIterator.hasNext();
}
@Override
public E next() {
if(!hasNext()) throw new NoSuchElementException("The iterator is empty");
return delegateIterator.next();
}
@Override
public void remove() {
delegateIterator.remove();
}
}
@Override
public Iterator<E> iterator() {
return new MyIterator();
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
if(delegate == null) return false;
return delegate.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
if(delegate==null) return false;
return delegate.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection<?> c) {
if(delegate == null) return false;
return delegate.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
if(delegate == null) return false;
return delegate.retainAll(c);
}
@Override
public void clear() {
if(delegate == null) return;
delegate.clear();
}
}