A book I am reading on Java tells me that the following two pieces of code are equivalent:
public <T extends Animal> void takeThing(ArrayList<T> list)
public void takeThing(ArrayList<? extends Animal> list);
On the opposite page, I am informed that the latter piece of code uses the '?' as a wildcard, meaning that nothing can be added to the list.
Does this mean that if I ever have a list (or other collection types?) that I can't make them simultaneously accept polymorphic arguments AND be re-sizable? Or have I simply misunderstood something?
All help/comments appreciated, even if they go slightly off topic. Thanks.
Does this mean that if I ever have a list (or other collection types?) that I can't make them simultaneously accept polymorphic arguments AND be re-sizable?
No.
The two pieces of code are not completely equivalent. In the first line, the method takeThing has a type parameter T. In the second line, you're using a wildcard.
When you would use the first version, you would specify what concrete type would be used for T. Because the concrete type is then known, there's no problem to add to the list.
In the second version, you're just saying "list is an ArrayList that contains objects of some unknown type that extends Animal". What exactly that type is, isn't known. You can't add objects to such a list because the compiler doesn't have enough information (it doesn't know what the actual type is) to check if what you're adding to the list should be allowed.
Usually, if adding to a list is involved inside a method that accepts just the list without the thing to add, you'll have somewhere else something that is an Animal and you'll want to add it to the list. In this case your method must be declared so that all the list types it accepts allow adding an Animal into them. This will have to be a List<Animal> or a list of some supertype of Animal. It can't possibly be a List<Dog>— the element you are adding could be any Animal.
This is where the concept of the lower bound, and the keyword super, come in. The type declaration List<? super Animal> matches all the acceptable types as described above. On the other hand, you won't be able to get elements out of such a list in a typesafe way because they can in general be of any type at all. If a method wants to both add and get elements of declared type Animal, the only valid type it can accept is a List<Animal>.
Related
There is the unmodifiableList method in the Collections class. It returns a List<T> but in the parameters it accepts List<? extends T>.
So if I understand this right then this method accepts a List which has T objects or objects that inherited from T class.
But I don't understand why the <? extends T> part in the parameter. I mean the parameter determines the return type of the method. If the method is called with List<Animal> then the return will be List<Animal> so it is going to be the same. Why we need this <? extends T>? Why don't we need just List<T> in the parameter list? I don't understand this.
If you could provide an example I would be happy about it.
Thank you in advance!
So if I understand this right then this method accepts a List which has T objects or objects that inherited from T class
This is oversimplifying matters.
a List<Number> can contain solely integers. The point of a List<Number> is that it is constrained to contain only number instances. Not that each instance MUST be Number and specifically Number - that would be impossible, as Number is abstract (no instances of Number itself can possibly exist, only instances of some subclass of it). The only difference between a List<Integer> containing only integers and a List<Number> containing only integers, is that you can add, say, a Double instance to that List<Number>, but you can't add it to a List<Integer>.
Because a method that takes, as argument, a List<Something> could invoke .add(), the type system needs to worry about the difference. It needs to do so even if this method does not, in fact, call add at all, and never intends to. The type system doesn't know that, and you're free to change the body of a method in some future version without that breaking backwards compatibility, thus, it matters. Even if you feel like it does not.
That then also explains your question:
If you have some method that demands a List<Number>, then you may provide a List<Integer> to Collections.unmodifiableList, and that's fine - Collections.uL will give you that List<Number>. This would ordinarily be broken, in that you can invoke .add(someDouble) which you should not be doing to a list of integers, but .add doesn't work on an unmodifiable, so it's fine.
List<? extends T> means it also accepts lists of subtypes.
Imagine having a class Plant and a class Tree that extends Plant.
You could create an unmodifiable List of Plants using a List<Tree> because Collections.unmodifiableList accepts lists of any subtype of T.
If it was List<T>, it would accept a List<Plant> as a parameter in order to create an unmodifiable List<Plant> but you could not create an unmodifiable List<Plant> using a List<Tree> as parameter.
I understand that one reason Lower-bounded wildcards exist is so that a collection is not immutable when adding new elements.
E.g.
List<? extends Number> obj = new ArrayList<>();//Now this list is immutable
obj.add(new Integer(5));//Does not compile
List<? super Number> objTwo = new ArrayList<>();//This list is mutable
objTwo.add(new Integer(5));//Compiles
The following does not compile because I tried to get the long value of numbers.
Q1: What methods would I be able to use? Only Objects methods?:
public void testLowerBounds(List<? super Number> numbers){
if (!numbers.isEmpty()){
System.out.println(numbers.get(0).longValue());//Does not compile
}
}
How my question came about:
I am currently learning about streams and the book specifies the following stream method:
Optional<T> min(Comparator<? super T> comparator)
And implements it as follows:
Stream<String> s = Stream.of("monkey", "ape", "bonobo");
Optional<String> min = s.min((s1, s2) -> s1.length()—s2.length());
Q2: How is the comparator allowed to use string methods when is used?
If I had to answer Q2: I would say that optional is specifying "You have to pass me an implementation of Comparator that has a generic type "String" or something that implements "String". Would I be correct in saying this?
Looking forward to your response.
First of all, you should not confuse wildcard type parameters with mutability. Having a wildcard in a List’s element type does not prevent modifications, it only imposes a few practical restrictions to what you can do with the list.
Having a list declared like List<? extends Number> implies that the referenced list has an actual element type of Number or a subclass of Number, e.g. it could be a List<Integer> or List<Double>. So you can’t add an arbitrary Number instance as you can’t know whether it is compatible to the actual element type.
But you can still add null, as the null reference is known to be compatible with all reference types. Further, you can always remove elements from a list, e.g. call remove or clear without problems. You can also call methods like Collections.swap(list, index1, index2), which is interesting as it wouldn’t be legal to call list.set(index1, list.get(index2)) due to formal rules regarding wildcard types, but passing the list to another method that might use a non-wildcard type variable to represent the list’s element type works. It’s obviously correct, as it only sets elements stemming from the same list, which must be compatible.
Likewise, if you have a Comparator<Number>, you can call Collections.sort(list, comparator), as a comparator which can handle arbitrary numbers, will be able to handle whatever numbers are actually stored in the list.
To sum it up, having ? extends in a collection’s element type does not prevent modifications.
As said, you can’t insert arbitrary new elements into a list whose actual element type might be an unknown subclass of the bound, like with List<? extends Number>. But you are guaranteed to get a Number instance when retrieving an element, as every instance of subtype of Number is also an instance of Number. When you declare a List<? super Number>, its actual element type might be Number or a super type of Number, e.g. Object or Serializable. You can insert arbitrary Number instances, as you know it will be compatible to whatever actual element type the list has, as it is a super type of number. When you retrieve an instance, you only know that it is an instance of Object, as that’s the super type of all instances. To compare with the ? extends case, having a ? super declaration does not prevent reading, it only imposes some practical limitations. And likewise, you can still pass it to Collections.swap, because, regardless of how little we known about the actual type, inserting what we just retrieved from the same list, works.
In your second question, you are confusing the sides. You are now not looking at the implementation of min, but at the caller. The declaration of min(Comparator<? super T> c) allows the caller to pass any comparator being parameterized with T or a super type of T. So when you have a Stream<String>, it is valid to pass a Comparator<String> to the min method, which is exactly, what you are implementing via the (s1, s2) -> s1.length()—s2.length() lambda expression (though, I’d prefer Comparator.comparingInt(String::length)).
Within the implementation of min, there is indeed no knowledge about what either, T or the actual type argument of the Comparator, is. But it’s sufficient to know that any stream element that is of type T can be passed to the comparator’s compare method, which might expect T or a super type of T.
I'm having difficulty understanding wildcards in Java generics. Specifically I have the following questions:
If we have a LinkedList<?>, why can we not add an Object to it? I understand that it doesn't know the type of the list, but wouldn't adding an Object to the list have us covered in any situation?
Similar to the question above, if we have LinkedList<? extends Number>, why can we not add a Number to it?
Finally, if we have LinkedList<? super Number>, why can we add an Integer to the list, shouldn't we only be able to add things that are a superclass of Number?
I guess I'm trying to understand how wildcards work in general, I've read the Oracle tutorials on them, and a few other things, but I don't understand why they work I suppose.
You're confusing objects and types.
Unlike simple generic parameters, wildcards describe the type of the generic parameter.
A List<? super Number> isn't a list of superclasses of Number; it's a list of some unknown type, where that type is a superclass of number.
A LinkedList<?> might be a LinkedList<Car>.
Since an Object is not a Car, you can't add an Object to it.
In fact, since you don't know anything about what type the list contains, you can't add anything to it. (except null)
Similarly, a LinkedList<? extends Number> might be a List<Long>, so you can't add an Integer to it. (since an Integer is not a Long)
On the other hand, a List<? super Number> is definitely allowed to contain Number or any derived class, since it can only be a list of one of Number's superclasses (eg, List<Object>)
I had a issue where (to simplify):
public void method(List<List<?>> list){...}
gave me a compilation error when called with:
method(new ArrayList<List<String>>()); // This line gives the error
After reading a similar thread, I understood that it would work if I were to rewrite the method signature as:
public void method(List<? extends List<?>> list){...}
Now, my question is, why does the following work then?
public <T> void method(List<List<T>> list){...}
Confusions do come when you deal with multi-level wildcard syntax. Let's understand what those types exactly mean in there:
List<List<?>> is a concrete parameterized type. It is a heterogenous collection of different types of List<E>. Since List<?> represent a family of all the instantiation of List, you can't really pass an ArrayList<List<String>> to List<List<?>>. Because, nothing stops you from adding a List<Integer> to it inside the method, and that will crash at runtime, had compiler allowed it.
List<? extends List<?>> is a wildcard parameterized type. It represents a family of different types of List<E>. Basically, it might be a List<ArrayList<String>>, List<LinkedList<Date>>, so on. It can be a list of any type that extend from a List<?>. So, it will be safe to pass a ArrayList<List<String>> to it, the reason being, you won't be allowed to add anything, but null to the list. Adding anything to the list will be a compile time error.
As for List<List<T>>, it is again a concrete parameterized type. And since you're dealing with a generic method now, the type parameter will be inferred to be the type that is passed for it. So, for an ArrayList<List<String>>, type T will be inferred as T. A generic method deals with the types that are declared with it. So, there is only a single type T here. All the lists you get out of List<List<T>> will certainly be a List<T> for any type T. So, it's a homogenous collection of that type of List. Inside the method, you can not add any arbitrary List<E> to the List<List<T>>, because the compiler doesn't know whether that type E is compatible with T or not. So, it is safe invocation.
Related:
Multiple wildcards on a generic methods makes Java compiler (and me!) very confused
Java HashMap nested generics with wildcards
What are multi-level wild cards? Confusion in syntax
When to use generic methods and when to use wild-card?
I think I found the answer in Angelika Langer's generics FAQ, "Case Study #3":
If a method signature uses multi-level wildcard types then there is always a difference between the generic method signature and the wildcard version of it. Here is an example. Assume there is a generic type Box and we need to declare a method that takes a list of boxes.
Example (of a method with a type parameter):
public static <T> void print1( List <Box<T>> list) {
for (Box<T> box : list) {
System.out.println(box);
}
}
Example (of method with wildcards):
public static void print2( List <Box<?>> list) {
for (Box<?> box : list) {
System.out.println(box);
}
}
Both methods are perfectly well behaved methods, but they are not equivalent. The generic version requires a homogenous list of boxes of the same type. The wildcard version accepts a heterogenous list of boxes of different type. This becomes visible when the two print methods are invoked.
The basic reason is that List<List<?>> is not a superclass of List<List<String>>.
A List<List<?>> could contain a List<Integer> and a List<String> for example.
The generic types must match exactly, otherwise you could get erroneous assignments made.
I am reading multi-level wild cards from AngelikaLangerGenericsFaq. I am pretty confused
about the syntax. The document says
The type Collection<Pair<String,?>> is a concrete instantiation of the
generic Collection interface. It is a heterogenous collection of
pairs of different types. It can contain elements of type
Pair<String,Long> , Pair<String,Date> , Pair<String,Object> ,
Pair<String,String> , and so on and so forth. In other words,
Collection<Pair<String,?>> contains a mix of pairs of different types
of the form Pair<String,?> .
The type Collection<? extends Pair<String,?>> is a wildcard
parameterized type; it does NOT stand for a concrete parameterized
type. It stands for a representative from the family of collections
that are instantiations of the Collection interface, where the type
argument is of the form Pair<String,?> . Compatible instantiations
are Collection<Pair<String,Long>> , Collection<Pair<String,String>> ,
Collection<Pair<String,Object>> , or Collection<Pair<String,?>> . In
other words, we do not know which instantiation of Collection it
stands for.
As a rule of thumb, you have to read multi-level wildcards top-down.
I am confused about the following points.
Can someone elaborate on these three quotes with example. I am totally lost into the syntax
Document says, para-1 is the concrete instantiation of a generic type and other is not the concrete instantiation? How is that?
What does it mean to read the wild-cards top down?
What is the advantage of multi-level wild cards?
Can someone elaborate these points. Thanks.
Can someone elaborate on these three quotes with example. I am totally lost into the syntax
Well, it wouldn't make sense to write those 3 quotes again here, as I can't give a better explanation than that. Instead, I will try to answer your other questions below, then possibly you will understand the answer to this one too. If not, you can ask your query again and I'll try to elaborate a little further.
Document says, para-1 is the concrete instantiation of a generic type and other is not the concrete instantiation? How is that?
A concrete instantiation is the one in which all the type arguments are concrete types, and are known at compile time. For e.g., List<String> is a concrete instantiation, because String is a concrete type. Its type is known at compile time. Whereas, List<? extends Number> is not a concrete type, because ? extends Number can be any type that extends Number. So, its type is unknown at compile time. Similarly, Map<String, Integer> is a concrete instantiation of generic type Map<K, V>.
In the case of multi-level type parameters, List<List<? extends Number>>, the outer List is a concrete instantiation of List<E>, because the type of elements is known to be a List at compile time, although the inner List is a wildcard instantiation, as the type of elements stored can be Integer, Double, any subclass of Number. But that paragraph is talking about the outer type only. And the outer type can only contain List type.
That's why the first paragraph said, it's a heterogenous collection of Pair, because the actual type parameter of Pair can be anything, but that is certain to be Pair and nothing else.
What does it mean to read the wild-cards top down?
Talking in layman's term, it means from left-to-right. While determining the type of the parameterized type, you first see the outermost type parameter. Then if that type parameter is itself a parameterized type, then you move onto the type parameters of that parameterized type. So, we read the type parameters, from left-to-right.
What is the advantage of multi-level wild cards?
Suppose you want to create a List of List of Fruits. Now your inner List can contain any kind of of fruits. An apple is also a fruit, and a banana is also a fruit. So, you have to make sure that you get all of them. Now, since generic types are invariant, in the sense, List<Apple> is not the same as List<Fruit>, you can't add a List<Apple> if your type of list is List<List<Fruit>>. For that you would need to use wildcards like this - List<List<? extends Fruit>>, which can now take List<Apple>, List<Banana>, list of any fruit.
Generic types with wildcards are really "existential" types. If you're familiar at all with logic, you can read G< ? extends T > as ∃S extends T:G< S >.
Angela's explanation about reading types "top down" really means that the imaginary existential quantifier implied by a type that contains a ? in it is always as close as possible to the ?. For example, you should mentally rewrite G< H< ? extends T > > to G<∃S extends T:H< S > >. Since there's no quantifier on the outside, it's called concrete.