Can someone help me with understanding logic behind this code:
import java.util.List;
import java.util.Arrays;
interface DoubleValue<T> {
public void dv(T e);
}
public class InTest2 {
public static void main(String[] a) {
DoubleValue<Number> func = e -> System.out.println(e.doubleValue());
List<Number> l = Arrays.asList(1, 2, 3);
InTest2.sumOfListNotWorking(l, func);
InTest2.sumOfListWorking(l, func);
InTest2.sumOfListWorkingSuper(l, func);
}
// I thought this should work
public static void sumOfListNotWorking(List<? extends Number> list, DoubleValue<? extends Number> f) {
for (Number n : list)
f.dv(n); // This line give error: The method dv(capture#2-of ? extends Number) in the type DoubleValue<capture#2-of ? extends Number> is not applicable for the arguments (Number)
}
public static void sumOfListWorking(List<? extends Number> list, DoubleValue<Number> f) {
for (Number n : list)
f.dv(n);
}
public static void sumOfListWorkingSuper(List<? extends Number> list, DoubleValue<? super Number> f) {
for (Number n : list)
f.dv(n);
}
}
sumOfListNotWorking:
Here I pass to DoubleValue.dv(<? extends Number> e) a Number and I thought it's OK.
But compiler says that it's not. Why?
I expect with DoubleValue<Number>.dv as e -> e.doubleValue() this should be typical consumer: I get value <? extends Number> and do something with it.
sumOfListWorkingSuper:
Behavior of sumOfListWorkingSuper puzzles me too.
Interface DoubleValue<? super Number> can't be a consumer cause value of <? super Number> can't be changed in place (Number is immutable), but compiler is OK with it.
UPDATE:
Apparently I didn't understand correctly logic of "producer" and "consumer".
sumOfListNotWorking:
This method doesn't compile because I use:
List<? extends Number> list as a producer (in method I take out
values from list with loop).
DoubleValue<? extends Number> as a consumer (in method I pass Number to f.dv(n)), but when I try to pass value Number to f compiler told me that f is defined as a producer (<? extends Number> - have some values of Number or it's children) and it can not accept any values. What if I passed to f argument DoubleValue<Integer> then I would try to put Number where should be Integer - this isn't possible. All this error happens because I define a producer instead of a consumer.
Thanks for pointing out word accept in logic of a consumer and a producer.
List<? extends Number> means "we don't know what this List contains, but whatever it is, it is a descendant of Number or Number itself."
Similarly, DoubleValue<? extends Number> means "we don't know what this DoubleValue can accept to operate with, but whatever it is it accepts, it is a descendant of Number or Number itself".
Here the relevant part is "we don't know what it accepts". We don't know, so you can't give anything to it and expect it will be accepted: because you don't know if it is accepted. The rest of the information is irrelevant. It's relevant in a List<? extends Number> because there at least we know that whatever elements it gives out, can be safely cast to Number after they're given out. But your DoubleValue class doesn't give out anything. It only takes in things. So all that "but we know that it is a descendant of" is completely useless.
<? extends Stuff> is useful on classes that give out objects. It's useless on those that don't give out objects.
<? super Stuff> is useful on classes that take in objects. It's useless on those that don't take in objects.
In addition to #kumesana's answer, this is how you can fix your method:
public static <T extends Number> void sumOfListNotWorking(
List<? extends T> list,
DoubleValue<? super T> f) {
for (T n : list)
f.dv(n);
}
You only needed to make that "unknown" type in wildcards known (T).
Also see the PECS rule. Here, list provides items (i.e. it is a producer), f accepts items (it is a consumer). So type in list should extend T, type in f should super T. This allows passing List<Integer> and DoubleValue<Number>.
Related
This question already has an answer here:
Capturing wildcards in Java generics
(1 answer)
Closed 6 years ago.
<T extends Number> void m1(List<T> list) {
list.add(list.get(0));
}
void m2(List<? extends Number> list) {
list.add(list.get(0));
}
I found difficult to understand the difference between above two methods.
First method m1() compiles successfully, but method m2() produces a compiler error:
The method add(capture#1-of ? extends Number) in the type List<capture#1-of ? extends Number> is not applicable for the arguments (capture#2-of ? extends Number)
Because you cant add an iten on a list of type with upper bounds! You could have a List or List, where one doesnt fit in the other for modifications operations!
List<? extends Number> list = new ArrayList<Integer>();
List<? extends Number> list = new ArrayList<Double>();
List<? extends Number> list = new ArrayList<Long>();
In this case, the variable list could have any type in instance that extends Number. So you can pass it in your method, for example. But there, you don't really know which the type could be. You could have a ArrayList<Integer> and saying to it add a new Double. In compile time makes sense, because Double extends Number, but in runtime the list could no be of this type and throw an Exception.
Just remember that, when you use the upper bounds, <? extends T>, you can't modify the list, just read it! There is the Oracle tutorial (see Wildcards chapter contents - Upper Bounded Wildcards, Lower Bounded Wildcards etc.)
This question already has answers here:
Why adding an element (of correct type) into a List through a method of <?> is a compilation error? [duplicate]
(1 answer)
How can I add to List<? extends Number> data structures?
(7 answers)
Closed 9 years ago.
I have:
class Document { ... }
class DocumentCluster extends Document { ... }
And I'm trying to define a set of documents this way:
Set<? extends Document> docs = new HashSet<Document>();
However, when I'm trying to insert a document to my set:
docs.add(d);
I'm getting:
The method add(capture#10-of ? extends Document) in the type Set<capture#10-of ? extends Document> is not applicable for the arguments (Document)
What am I doing wrong?
Because it might only allow objects of type B.
A classic question, answered a million of times. Non-intuitive, but also not a design bug of Java.
Here is the classic example: let A be Fruit.
Can I put an Apple into a Set<? extends Fruit>?
No, because it could be a Set<Banana> which obviously must not contain apples.
? extends Fruit says some specific kind of fruit, and not "any kind of fruit". Then it would be a Set<Fruit> which indeed can take any kind of Fruit.
As a rule of thumb:
when putting ? super Fruit is convenient. It takes "at least" fruits
when getting ? extends Fruit is convenient. It may return only one kind of fruit, but they will all be fruit.
Consider this method:
public static double computeAverage(Collection<? extends Number> col) {
double sum = 0.;
for (Number n : col) {
sum += n.doubleValue();
}
return sum / n.size();
}
This method can work with List<Integer>. Because it does not put Double into the list, but only takes Number objects out.
public static void put(Collection<? super Number> col, Number n) {
col.put(n);
}
Here, we have the opposite case. We need a list that accepts arbitrary numbers (otherwise, we could not put the unspecific number in it). It may accept more, though:
put(new List<Object>(), (Double) 1.);
is valid, because I may put doubles into a list of Objects.
But the compiler correctly prevents put( new List<Integer>(), (Double) 1.).
It can get much messier than that:
public static <I,O> void transfer(Collection<? extends I> input,
Collection<? super O> output,
Converter<? super I, ? extends O> converter) {
for (I inobj : input) {
O outobj = converter.convert(inobj);
output.put(outobj);
}
}
But the compiler may be unable to figure out I and O automatically for you every time.
Set<? extends A> can't be added to because you don't exactly what type you are adding to the collection, only that you are adding SOMETHING that extends A. You can guarentee that when you use get() you will get a class that extends A, but when you use add() because you don't know the definitive type, you can't add to the collection
If you want to take advantage of polymorphism, use Set<A>. This will do the exact same thing - any member that is type compatible, ie, extends, from A can be placed in the Set<K>.
EDIT:
#Anony-Mousse explained this much better with an example.
this is from HeadFirst Java: ( page 575 )
This:
public <T extends Animal> void takeThing(ArrayList<T> list)
Does the same thing as this:
public void takeThing(ArrayList<? extends Animal> list)
So here is my question: if they are exactly same, why don't we write
public <? extends Animal> void takeThing(ArrayList<?> list)
or
public void takeThing(ArrayList<T extends Animal> list)
Also, when would it be useful to use a ? instead of a T in a method declaration ( as above ) with Generics, or for a Class declaration? What are the benefits?
The big difference between
public <T extends Animal> void takeThing(ArrayList<T> list)
and
public void takeThing(ArrayList<? extends Animal> list)
is that in the former method you can refer to "T" within the method as the concrete class that was given. In the second method you cannot do this.
Here a more complex example to illustrate this:
// here i can return the concrete type that was passed in
public <T extends Animal> Map<T, String> getNamesMap(ArrayList<T> list) {
Map<T, String> names = new HashMap<T, String>();
for (T animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
// here i have to use general Animal
public Map<Animal, String> getNamesMap(ArrayList<? extends Animal> list) {
Map<Animal, String> names = new HashMap<Animal, String>();
for (Animal animal : list) {
names.put(animal, animal.getName()); // I assume there is a getName() method
}
return names;
}
With the first method if you pass in an List of Cats you get a Map with Cat as key. The second method would always return a Map with general Animal key.
By the way this is not valid java syntax:
public <? extends Animal> void takeThing(ArrayList<?> list)
Using this form of generic method declaration you have to use a valid java identifier and not "?".
Edit:
The form "? extends Type" only applies to variable or parameter type declaration. Within a generic method declration it has to be "Identifier extends Type" as you are able to refer to the "Identifier" from within your method.
Wild cards are about co/contra variance of generics. I will try to make clear what this means by providing some examples.
Basically it is related to the fact that for types S and T, where S is a subtype of T, a generic type G<S> is not a valid subtype of G<T>
List<Number> someNumbers = new ArrayList<Long>(); // compile error
You can remedy this with wild cards
List<? extends Number> someNumbers = new ArrayList<Long>(); // this works
Please note, that you can not put anything into such a list
someNumbers.add(2L); //compile error
even (and more surprising for many developers):
List<? extends Long> someLongs = new ArrayList<Long>();
someLongs.add(2L); // compile error !!!
I think SO is not the right place to discuss that in detail. I will try to find some of the articles and papers that explain this in more detail.
Binding the type to a type parameter can be more powerful, depending on what the method is supposed to do. I'm not sure what takeThing is supposed to do, but imagine in general we have a method with one of these type signatures:
public <T extends Animal> void foo(ArrayList<T> list);
//or
public void foo(ArrayList<? extends Animal> list);
Here's a concrete example of something you can only do with the first type signature:
public <T extends Animal> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
In this case T is required to inform the type checker that the element being removed from the list is an OK element to add to the list.
You could not do this with a wildcard because, as the wildcard has not been bound to a type parameter, its context is not tracked (well, it is tracked, through "captures", but it's not available to leverage). You can get more information on this in another answer I've given: How do generics of generics work?
If you write ? extends T you say "anything that is a T or more specific". For example: a List<Shape> can have only Shapes in it, while a List<? extends Shape> can have Shapes, Circles, Rectangles, etc.
If you write ? super T you say "anything that is a T or more general". This is less often used, but has it's use cases. A typical example would be a callback: if you want to pass a Rectangle back to a callback, you can use Callback<? super Rectangle>, since a Callback<Shape> will be able to handle Rectangles as well.
Here's the relevant Wikipedia article.
If your takeThing method needs to add elements to the list parameter, the wildcard version will not compile.
The interesting case is when you are not adding to the list and both versions seem to compile and work.
In this case, you would write the wildcard version when you want to allow different type of animals in the list (more flexibility) and the parameter version when you require a fixed type of animal in the list: the T type.
For example the java.util.Collection declares:
interface Collection<E> {
...
public boolean containsAll(Collection<?> c);
...
}
And suppose you have the following code:
Collection<Object> c = Arrays.<Object>asList(1, 2);
Collection<Integer> i = Arrays.<Integer>asList(1, 2, 3);
i.containsAll(c); //compiles and return true as expected
If the java.util.Collection would be:
interface Collection<E> {
...
public boolean containsAll(Collection<E> c);
...
}
The above test code would not compile and the flexibility of the Collection API would be reduced.
It worth noting that the latter definition of containsAll has the advantage of catching more errors at compile time, for example:
Collection<String> c = Arrays.asList("1", "2");
Collection<Integer> i = Arrays.asList(1, 2, 3);
i.containsAll(c); //does not compile, the integer collection can't contain strings
But misses the valid test with a Collection<Object> c = Arrays.<Object>asList(1, 2);
Java Generics Wildcards usage is governed by the GET-PUT Principle (Which is also known as the IN-OUT principle). This states that:
Use an "extends" wildcard when you only get values out of a structure, Use a "super" wildcard when you only put values into a structure, and do not use wildcards when you do both. This does not apply to a method's return type. Do not use a wildcard as a return type. See example below:
public static<T> void copyContainerDataValues(Container<? extends T> source, Container<? super T> destinationtion){
destination.put(source.get());
}
I can't find any example where wildcards can't be replaced by a generic.
For example:
public void dummy(List<? extends MyObject> list);
is equivalent to
public <T> void dummy(List<T extends MyObject> list);
or
public <T> List<? extends T> dummy2(List<? extends T> list);
is equivalent to
public <T, U> List<U extends T> dummy(List<U extends T> list);
So I don't undertand why wildcard was created as generics is already doing the job. Any ideas or comments?
Nope, it is not always replaceable.
List<? extends Reader> foo();
is not equivalent to
<T> List<T extends Reader> foo();
because you don't know the T when calling foo() (and you cannot know what List<T> will foo() return. The same thing happens in your second example, too.
The demonstration of using wildcards can be found in this (my) answer.
An easy answer is that, deeper level wildcards can't be replaced by a type variable
void foo( List<List<?>> arg )
is very different from
<T>
void foo( List<List<T>> arg)
This is because wildcard capture conversion is only applied to 1st level wildcards. Let's talk about these.
Due to extensive capture conversion, in most places, compiler treats wildcards as if they are type variables. Therefore indeed programmer can replace wildcard with type variables in such places, a sort of manual capture conversion.
Since a type variable created by compiler for capture conversion is not accessible to programmer, this has the restricting effect mentioned by #josefx. For example, compiler treats a List<?> object as a List<W> object; since W is internal to compiler, although it has a method add(W item), there's no way for programmer to invoke it, because he has no item of type W. However, if programmer "manually" converts the wildcard to a type variable T, he can have an item with type T and invoke add(T item) on it.
Another rather random case where wildcard can't be replaced type variable:
class Base
List<? extends Number> foo()
class Derived extends Base
List<Integer> foo()
Here, foo() is overriden with a covariant return type, since List<Integer> is a subtype of List<? extends Number. This won't work if the wildcard is replaced with type variable.
There is a usage difference for your examples.
public <T> List<? extends T> dummy2(List<? extends T> list);
returns a list that can contain an unknown subtype of T so you can get objects of type T out of it but can't add to it.
Example T = Number
List<? extends Number> l = new ArrayList<Integer>(Arrays.asList(new Integer(1)));
//Valid since the values are guaranteed to be a subtype of Number
Number o = l.get(0);
//Invalid since we don't know that the valuetype of the list is Integer
l.add(new Integer(1));
So the wildcard can be used to make some operations invalid, this can be used by an API to restrict an interface.
Example:
//Use to remove unliked numbers, thanks to the wildcard
//it is impossible to add a Number
#Override public void removeNumberCallback(List<? extends Number> list){
list.remove(13);
}
I have a question on the use of wildcards in Java's generic types: what is the basic difference between List<? extends Set> and List<T extends Set>? When would I use either?
Two reasons:
To avoid unnecessary casts:
You have to use the T variant for cases like this:
public <T extends Set> T firstOf(List<T> l) {
return l.get(0);
}
With ? this would become:
public Set firstOf2(List<? extends Set> l) {
return l.get(0);
}
...which doesn't give the same amount of information to the caller of the firstOf method. The first version allows the caller to do this:
SubSet first = firstOf(listOfSubSet);
while with the second version, you are forced to use a cast to make it compile:
SubSet first = (SubSet)firstOf(listOfSubSet);
To enforce matching argument types:
public <T extends Set> boolean compareSets(List<T> a, List<T> b) {
boolean same = true;
for(T at : a) {
for (T bt: b) {
same &= at.equals(bt);
}
}
return same;
}
There is no direct equivalent using ? instead of T for this. Note that due to Java's single-dispatch, in the above version, the compiler will call at's equals(T) method which may well differ from at's equals(Set) or equals(Object) method.
The difference here is that in the second version, you have a type variable T that refers to the specific subtype of Set that the List contains. You need this in cases where you need to ensure that something else is the same type as the type contained in the list. A couple simple examples:
// want to ensure that the method returns the same type contained in the list
public <T extends Set> T something(List<T> list) {
...
}
// want to ensure both lists contain the exact same type
public <T extends Set> List<T> somethingElse(List<T> first, List<T> second) {
...
}
Simple rule: Use a type variable T extends Foo in your method signature if the same type is necessary in two places. Method parameters are each one place and the method return type is another place. Use the wildcard ? extends Foo if you just need to ensure you're dealing with "something that is a Foo" in one place.
Aside: don't use the raw type Set.
You use List<? extends Set> when you declare a varlable. For example:
List<? extends Number> l = new ArrayList<Integer>();
List<T extends Number> can be used in class or methode declaration. This will allow you to write T instead of <? extends Number> later on in the function.
public <T extends Number> int addAll(List<T> list) {
int result = 0;
for (T t : list) {
result += t.intValue();
}
return result;
}
We use wildcards to specify that the type element matches anything. The ? stands for unknown type.
List<? extends Set> is an example of a bounded wildcard and that states that the list can accept any subtype of a Set (e.g. HashSet)
List<T extends Set>, on the other hand is, allows T to be bounded to a type that extends Set.
I use wildcards when I need a collection of data irrespective pf it's exact type.
A wildcard type G<? extends A> is a super type of any G<Ai> where Ai is a subtype of A
In another word, G<? extends A> is the union type of G<A0>, ..., G<An>.