Reputation: 20094
This is part of the Java (1.6) Collection interface:
public interface Collection<E> extends java.lang.Iterable<E> {
/* ... */
boolean containsAll(java.util.Collection<?> objects);
boolean addAll(java.util.Collection<? extends E> es);
boolean removeAll(java.util.Collection<?> objects);
boolean retainAll(java.util.Collection<?> objects);
/* ... */
}
Why does addAll
have <? extends E>
while removeAll
has <?>
Upvotes: 13
Views: 1406
Reputation: 15656
With addAll you want to be able to add all elements that are a subtype of the generic type. This includes adding all elements of a List<String>
to a List<Object>
. We use ? extends E
to accept any Collection that contains the type stored in this collection or any subtype.
boolean addAll(java.util.Collection<? extends E> es);
List<Number> numbers = ...;
List<Integer> integers = ...;
numbers.addAll(integers);//works
boolean addAll(java.util.Collection<E> es);
numbers.addAll(integers);//does not work E != Integer
we can't use ?
as that would remove any security provided by generics.
boolean addAll(java.util.Collection<? extends E> es);
List<Number> numbers = ...;
List<Integer> integers = ...;
List<String> strings = ...;
numbers.addAll(integers);//works
numbers.addAll(strings);//error
boolean addAll(java.util.Collection<?> es);
numbers.addAll(strings);//works - now we have strings in our Number collection
We can use ?
to remove objects since trying to remove a String from List of Numbers wont affect a List<Number>
.
boolean removeAll(java.util.Collection<?> objects);
List<Objects> objects = ...;
List<Integer> integers = ...;
List<Number> numbers = ...;
numbers.removeAll(objects);//works
numbers.removeAll(integers);//works
boolean removeAll(java.util.Collection<? extends E> objects);
numbers.removeAll(objects);//does not work
numbers.removeAll(integers);//works
boolean removeAll(java.util.Collection<? super E> objects);
numbers.removeAll(objects);//works
numbers.removeAll(integers);//does not work
Upvotes: 0
Reputation: 19500
To remove restriction is not needed, so only <?>
, but while adding we have to check and then add for type safety, so addAll is with restriction <? extends E>
Upvotes: 0
Reputation: 116306
For any collection containing elements of type E
, addAll
must be able to deal with input collections not just of E
, but all of its subclasses as well. Hence <? extends E>
. Without this, you could not add all elements of a List<Integer>
to a List<Number>
, which would clearly not be right.*
For removal, the limits need not be so strictly set, and there is no harm in trying to remove elements of a collection of some totally unrelated type. E.g. you can have a collection of Number
s, about which you happen to know that it only contains Integer
s, so passing it to removeAll
on a List<Integer>
should work fine, and it would be stupid for the compiler to disallow this.
Note that according to the Javadoc, removeAll
may optionally throw a ClassCastException
, depending on implementation.
*The reason behind this is that in Java, generics are invariant. For more details, see e.g. this thread.
Upvotes: 7
Reputation: 55886
I did not know, I googled. I got this explaination here: http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html
Copying the part:
One element of the generifed Collections API that is often confusing at first is the signatures of containsAll(), removeAll(), and retainAll(). You might expect the signatures for remove() and removeAll() to be:
interface Collection<E> { public boolean remove(E e); // not really public void removeAll(Collection<? extends E> c); // not really }
But it is in fact:
interface Collection<E> { public boolean remove(Object o); public void removeAll(Collection<?> c); }
Why is this? Again, the answer lies in backward compatibility. The interface contract of x.remove(o) means "if o is contained in x, remove it; otherwise, do nothing." If x is a generic collection, o does not have to be type-compatible with the type parameter of x. If removeAll() were generified to only be callable if its argument was type-compatible (
Collection<? extends E>
), then certain sequences of code that were legal before generics would become illegal, like this one:// a collection of Integers Collection c = new HashSet(); // a collection of Objects Collection r = new HashSet(); c.removeAll(r);
If the above fragment were generified in the obvious way (making c a
Collection<Integer>
and r aCollection<Object>
), then the code above would not compile if the signature of removeAll() required its argument to be aCollection<? extends E>
, instead of being a no-op. One of the key goals of generifying the class libraries was to not break or change the semantics of existing code, so remove(), removeAll(), retainAll(), and containsAll() had to be defined with a weaker type constraint than they might have had they been redesigned from scratch for generics.
Upvotes: 12
Reputation: 4180
Who cares what you try to remove ?
Adding is something else; we wouldn't want to end up with something strange in our collection.
as requested; an example:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class Main {
private static class A {
}
public static void main(String[] args) {
Collection<A> collection_A = new ArrayList<A>();
Collection<String> collection = new ArrayList<String>();
// no problem to try and remove things that wouldn't be there in the first place; either way, they are gone afterwards
collection.removeAll(collection_A);
// we can't allow this; you would end up with things in your collection that don't belong there
collection.addAll(collection_A);
}
}
Upvotes: 0
Reputation: 328913
A simple example to illustrate what has been said:
public class Test {
public static void main(String[] args) {
List<String> l = new ArrayList<String>();
System.out.println(l.remove(new Object())); //false
System.out.println(l.contains(new Object())); //false
// l.add(new Object()); // does not compile
}
}
Upvotes: 0
Reputation: 888223
<?>
is less restrictive than <? extends E>
.
There is nothing wrong with removing an orange from a collection of apples; there are a lot of things wrong with adding an orange to a collection of apples.
Upvotes: 3
Reputation: 16200
When you add item to your collection you want to be sure that they do have a certain type.
When you remove them, only those in the collection are removed. Regardless of their type.
Upvotes: 2
Reputation: 7347
when you add an object, it needs to be a subclass (or sub-subclass, etc.) of the main type. When you remove an object, it returns it as the type oc the collection. This is a good example of polymorphism in action.
Upvotes: 0
Reputation: 2992
Java implements generics through erasure. These info are only for compilation time only. I guess the java collection designers did this to retain more ascendent compatibility with pre-generics java version.
Upvotes: 0