mercredi 4 février 2015

Do wildcards in Java generics restrict or increase flexibility?


I have read many sources about wildcards and Java generics. Even though I have seen many explanations and answers, none of them seems correct.


The question is very simple: Do wilcards in Java generics increase flexibility?


My understand is "No". Wildcards in Java generics (wilcards) actually decrease flexibility. When I first looked at and used Java generics mechanism, I rarely/never used wildcards. Very often I saw and used the form <T> abc(T xt). One day I got a test question about super and later I started looking at wildcards more closely.


Many sources and in particular: Effective Java 2nd gives an example as follows to show how wildcards increase flexibility.



public class Stack<E> {
...
public void pushAll(List<E> list) {...}
...
}


The books goes on and says that since we should be able to use List of anything extending E as argument to pushAll(List<E> list), this is not flexible enough. Therefore, the book suggest changing the signature of the method to pushAll(List<? extends E> list). Now if E is Number then we can even use List<Integer> as argument for pushAll(List<? extends Number> list). And that we have increased flexibility (of the API).


My understanding is that the other solution is not to use wildcards but to use the regular typing. In that case, if we change the method signature to



public <T extends E> void pushAll(List<T> list)


we will achieve the same thing that the wildcard version wants to achieve. And now in the body of the method, not only we can read from list, we can also write into it. If we use the the wildcard version, we cannot write into that list any value other than null. So in this view, wildcards actually decrease flexibility, not increase.


All in all, it looks to me that wildcards are actually used to decrease flexibility so that <? extends X> discourages people from writing into the object while <? super X> discourages people from reading the object (try it and you will get only Object as type of the returned value). The following example illustrates the <? super X> case.



public void popAll(List<? super E> list) {
Object x = list.get(0) // Only get Object as type here, reading is discouraged
}


We can change the signature to public <T extends E> void popAll(List<T> list). Now we can write or read as we want. There is no restriction.


So to sum up: All usages of wildcards can be substituted by typed parameter in the manner of <T extends E> (so there can be no need for the keyword super) . Using wildcards, we lose flexibility in the ability to both read and write into the object. Therefore, wildcards decrease flexibility.


Is it therefore true that wildcards in Java actually decrease flexibility? If not, how is my reasoning flawed?





Aucun commentaire:

Enregistrer un commentaire