The following code does not compile in Eclipse. It says "The method putHelper(List,int,E) in the type Abc is not applicable for the arguments (List <.capture#8-of extends E>",int,E)"
private <E> void putHelper(List<E> list, int i, E value) {
list.set(i, value);
}
public <E> void put(List<? extends E> list, int toPos, E value) {
// list.set(toPos,value);
putHelper(list, toPos, value);
}
I don't understand why it is so? Because the code below works fine.
public <E> void put(List<? extends E> list,int fromPos, int toPos) {
putHelper(list,fromPos,toPos);
}
private <E> void putHelper(List<E> list,int i, int j) {
list.set(j,list.get(i));
}
And I understand that here the helper method is able to capture the wildcard type, but why not in the earlier code?
EDIT: In the third case, if I change type parameter in the put method to List<.? super E> and when I try to call the put() method from another method which takes a list, Eclipse doesn't compile it. It says, "The method put(List<.? super E>,int,E) in the type Abc is not applicable for the arguments (List <.capture#6-of extends E>",int,E)"
public static <E> void insertAndProcess(List<? extends E> list) {
// Iterate through the list for some range of values i to j
E value = list.get(i);
//Process the element and put it back at some index
put(list, i+1, value);
//Repeat the same for few more elements
}
private static <E> void putHelper(List<E> list, int i, E value) {
list.set(i, value);
}
public static <E> void put(List<? super E> list, int toPos, E value) {
putHelper(list, toPos, value);
}
Here, how can insertAndProcess() call put() method and use it in its implementation, while the user can still be able to call both these methods with say ArrayList<.Integer>?
This is because of the Get and Put Principle also known by the acronym PECS which stands of Producer Extends, Consumer Super.
This is explained in this SO question: What is PECS (Producer Extends Consumer Super)?
But basically:
public <E> void put(List<? extends E> list, int toPos, E value) {
// list.set(toPos,value);
putHelper(list, toPos, value);
}
<? extends E>
can't be used here because the List
is being used as a consumer (it is taking elements) so it should use super
instead of extends
.
public <E> void put(List<? super E> list, int toPos, E value) {
// list.set(toPos,value);
putHelper(list, toPos, value);
}
EDIT
In your 2nd case, List
is acting as a producer because it is producing elements via the call to get()
so you can use extends
.
However, in your 3rd example, you are both getting and putting into the same list so I don't think you can use wildcards at all.
This compiles:
public static <E> void insertAndProcess(List<E> list) {
// Iterate through the list for some range of values i to j
E value = list.get(i);
// Process the element and put it back at some index
putHelper(list, i+1, value);
// Repeat the same for few more elements
}
Note that since we don't need to use any wildcards anyway because we are getting and setting from the same list so the type E
must be the same no matter what it is.