We use wildcard in the method args when we want to pass list containing objects of child class. But as shown below we can achieve the same functionality using Type parameter. So why we need wildcards ?
Scenario
Lets say we have base-class named Department and its sub-classes named Development & Sales.
Development & Sales are subtypes of Department but List & List are not subtypes of List.
So when we want to pass list of Development or Sales object as method arg which is accepting list of any type of Department we use wildcard. But inside the code we can see we can achieve the same without using wildcard.
As per Effective Java using wildcard in return type is really a bad choice. What are the other usecases where wildcard is really helpful?
class MyGenericsClass<T extends SuperClass> {
//These 2 methods works the same
<H> void unboundedMethod1(AnotherGenericClass<H> arg) {
}
void unboundedMethod2(AnotherGenericClass<?> arg) {
}
//These two methods works the same
<H extends SuperClass> void boundedMethod1(AnotherGenericClass<H> arg) {
}
void boundedMethod2(AnotherGenericClass<? extends SuperClass> arg) {
}
//These two methods works the same
<U extends Building> void boundedListMethod1(List<U> list){
}
void boundedListMethod2(List<? extends Building> list) {
}
//Why can't we write like this? Giving Compile time error
//<U> void notWorkingMethod1(List<U extends SuperClass> list){ //Statements }
//<T> void notWorkingMethod2(List<U extends SuperClass> list){ //Statements }
}
Inside the notWorkingMethods1 and notWorkingMethods2 why can't we pass Bounded Type parameter directly but we can do so by first declaring it before return type ?
First, your initial assumption that the two methods behave the same is incorrect.
Assume the generic classes were Lists. Try adding something of type H to List<H> and anything to List<?> and see if they behave the same.
Regarding the last question.
<U extends Building> void boundedListMethod1(List<U> list)
Says that U is a type that extends Building and List contains that type.
However,
<U> void notWorkingMethod1(List<U extends Building> list)
Says that there is some type U and a List that expects a type U that extends Building. Those two statements do not imply compatibility. U may not be a subClass of Building but the List expects it.
WildCards are helpful when you just want to do something without regard to type.
List<Map<String,Integer>> list = ....
for (Map<?,?> m : list) {
System.out.println(m);
}
They are also useful for copying types.
public <H> void copy(List<? extends H> src, List<? super H> dst) {
for (H a : src) {
dst.add(a);
}
}
Related
class Employee<T extends Number> { // valid
}
class Employee<? extends Number> { // invalid
}
private static void test(List<? super Number> list1) { // valid
}
private static <T>void test(List<T super Number> list1) { // invalid
}
what exactly is difference between ? and T and when to use what?
Why with class definition, ? doesn't work but it works with List and why T works with class definition but not with List?
Where to declare a generic
You can not use a generic type token T before introducing it.
In your method example you try to declare the T at the wrong spot, that is invalid syntax. You have to introduce it beforehand.
For the class example however, you have put it in the right spot.
Here is where you can introduce your generic type token on a class wide level:
public class Foo< HERE > { ... }
and thats how you do it for a method only:
public < HERE > void foo(...) { ... }
Bounded generics
In both cases you can bound your T, like T extends Number and then use it accordingly:
public class Foo<T extends Number> { ... }
// or
public <T extends Number> void foo(...) { ... }
After you have introduced your T, you will use it just like that. So List<T>, as an example.
public <T extends Number> void foo(List<T> list) { ... }
Note that T super Number is invalid on as it makes little sense and does not provide more information than just T or Number or simply Object, depending on what you are trying to achieve. You can read more about that at Java generic methods: super can't be used?
Wildcards
Wildcards are a different thing. They are not a generic type token that you have to introduce first, such as T. Instead, they clarify the type range you want to accept.
For example a method like
public static void foo(List<? super Dog> list) { ... }
can be called with a List<Dog>, a List<Animal> or even a List<Object>. We call such a list a consumer of Dogs. To be precise, these are all lists that would accept a dog, so list.add(new Dog()) will work.
On the other side, we have
public static void foo(List<? extends Dog> list) { ... }
which can be called with a List<Dog> or also a List<Chihuahua>. We call such a list a producer (or provider) of Dogs. To be precise, these are all lists that can provide dogs. So Dog dog = list.get(0) will work.
You can read more about the details of what wildcards are and how they work at What is PECS (Producer Extends Consumer Super)?
When to use which?
In general, you would use a generic type token T when you actually still need to maintain the type safety throughout your code. I.e. when you need to be able to give the type a name. Otherwise you use wildcards ?.
For example, suppose you want to create a method that takes in a list and an element to add to it:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
You need to introduce the T to ensure that the type of the list matches the given element. Otherwise someone could do addToList(dogs, cat), which you do not want.
If you do not have the need to actually name the type, you can also just use a wildcard. For example a method that takes a list and prints all its contents:
public static void printAll(List<?> list) {
for (Object object : list) {
System.out.println(object);
}
}
Can anyone please explain me below code
public <T extends Emp> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
I am trying to understand how Generics will apply on void return type.
Note: i have changed the code now it is not giving any error.
I am trying to understand how generics will apply on void return type.
This is only a syntax. Generics do not apply to void return type, they apply to the method as a whole.
The name and restrictions on the generic parameter need to go somewhere in the text of your program. In a class declaration they follow the class name in angular brackets. In a generic method declaration they follow the accessibility designator public, and precedes the return type void.
One could easily imagine an alternative placement of generic types, such as
public void foo<T extends Emp>(ArrayList<T> list) // Imaginary syntax
or even
public void foo(ArrayList<T> list) <T extends Emp> // Imaginary syntax
but Java designers decided on the placement before the return type designator.
Generics won't be applied to void.
If you say that the type is <T extends Emp>, you are saying, that any subtype of Emp can be applied in place of T.
In your code, You can use <T> instead of <T extends Emp> as you aren't doing anything with Emp
public <T> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
Regarding how it'll work, the type will be provided by you when you use this method and at compile time, java will place required casts automatically. So, if you are using this:
ArrayList<String> list = new ArrayList<>();
// Add some items into list
foo(list);
in that case, your foo() method will find out that type <T> is String and so, will behave something like:
public void foo(ArrayList<String> list) {
list.add((String)(list.remove(0)));
}
Given the following setup:
public class TestType {
public static void main(String[] args) {
List<Constants> list = new ArrayList<>();
accept(list); //Does not compile
}
static void accept(Iterable<MyInterface> values) {
for (MyInterface value : values) {
value.doStuff();
}
}
}
interface MyInterface<T> {
T doStuff();
}
enum Constants implements MyInterface<Integer> {
ONE, TWO, THREE;
#Override
public Integer doStuff() {
return ordinal();
}
}
Why won't the compiler accept the list as parameter to accept()?
List extends Iterable via Collection so that isn't the problem.
On the other hand, the compiler tells me that
incompatible types: java.util.List<enums.Constants> cannot be converted to java.lang.Iterable<enums.MyInterface>
But Constants IS a MyInterface... isn't it?
The problem is with how Generics work. Specifically, Generics are non-reified... meaning that the compiler will not see an Iterable<enum.Constants> as an Iterable<enum.MyInterface> even if Constants is a sub-class of MyInterface.
However, there is a way to get around it: Generic wildcards.
If you change static void accept(Iterable<MyInterface> values) to static void accept(Iterable<? extends MyInterface> values), it should work.
You need to use Iterable<? extends MyInterface> instead of Iterable<MyInterface> because even though Constants is a subtype of MyInterface, Iterable<Constants> is not a subtype of Iterable<MyInterface> - and I'll show you why:
If it was so (let's use List instead of Iterable for the next example), I would be able to do this:
List<Constant> constantsList = new ArrayList<Constants>(); // list of constants
List<MyInterface> ifaceList = constantsList; // you said this would be OK ...
// assume MyOtherImplementation is another implmentation of MyInterface
ifaceList.add(new MyOtherImplementation()); // OK, MyOtherImplementation implements MyInterface
Constant myConst = constantsList.get(0); // Oops! I just got an instance of MyOtherImplementation from List<Constant> - not cool.
Generic types do not inherit this way, although it may seem counter-intuitive at first glance. Using Iterable<? extends MyInterface> will allow you to use any Iterable (e.g., a List) of a type that extends MyInterface (e.g. Constants).
Consider this snipped code:
public class MaxSizeHandler extends AbstractValueHandler<Collection> {
}
and I use eclipse, and It warns me to add infer generic arguments type for Collection and the code changes like this:
public class MaxSizeHandler extends AbstractValueHandler<Collection<?>> {
}
My question is what's the problem if I don't put it, or what's the advantage if I put it?
Passing a raw Collection will imply that the Collection is not parametrized, hence you lose the ability to strongly type (i.e. at compile time) what goes in the Collection.
Passing a Collection<?> is not substantially different, as the wildcard will match anything extending Object.
Of course, it will remove the warning.
The best way would be to pass a Collection<MyObject> or a Collection<? extends MyObject>, etc.
you need to mention Collection type before itself in generic format like below :
public class MaxSizeHandler extends AbstractValueHandler<Collection<? extends T>> {
}
T-> type of collections
Otherwise java compiler will take as default type of collection.
Adding the correct type will allow the class to return the correct type of value, is there a specific type of Object your Collection will hold i.e Integer, then use AbstractValueHandler<Collection<Integer>>.
Depending how you're using the MaxSizeHandler class it may make sense to make this class itself generic. For example, if you need to iterate over the collection:
public class MaxSizeHandler<T>
extends AbstractValueHandler<Collection<? extends T>> {
public void handle(Collection<? extends T> coll) {
for(T item : coll) {
// ...
}
}
}
or if you need to add new items to the collection:
public class MaxSizeHandler<T>
extends AbstractValueHandler<Collection<? super T>> {
public void handle(Collection<? super T> coll) {
T item = createAnItem();
coll.add(item);
}
}
(These are just toy examples, as you haven't said what kind of methods AbstractValueHandler declares)
I am learning Java Generics. My understanding is that Generics parameterize Collections by type. In the Oracle tutorial there is the following comment:
In generic code, the question mark (?), called the wildcard,
represents an unknown type.
On the next page there is the following example of method declaration with an upper-bounded wildcard in the parameters:
public void process(List<? extends Foo> list)
Given that, I am wondering why this method declaration is illegal:
public void process(List<E extends Number> list)
while this one is legal:
public <E extends Number> void process(List<E> list)
When specifying the method parm types, you're using the generic type, so it has to be defined upfront. In this statement, you use E without definition
public void process(List<E extends Number> list) { /* ... */ }
However, in the second one, it is defined before the method return type (void):
public <E extends Number> void process(List<E> list) { /* ... */ }
There's not a much better answer than "because that was how the language was designed." But one way of thinking about it is that type parameters are treated like another list of arguments to the method: they have to all appear at once, in one (ordered) list.
You can call generic methods by passing the type arguments explicitly: for example, foo.<Integer, String>process(list). That means that the type parameters have to have an explicit order, just like normal value arguments.
To complete on #phoenix's answer, the problem in this statement
public void process(List<E extends Number> list) { /* ... */ }
is that the declaration of your generic type E is in the wrong place. The right place is before the return type:
public <E extends Number> void process(List<E> list) { /* ... */ }
However, another possible place to define your generic type would be in the class declaration itself:
class MyClass<E extends Number> {
public void process(List<E> list) { /* ... */ }
}
Approximately both are same , but i am using first one only.