Differencebetween Bounded Wildcard and Type Parameters

Java: bounded wildcards or bounded type parameter?

It depends on what you need to do. You need to use the bounded type parameter if you wanted to do something like this:

public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
if (shape.isPretty()) {
shapes.add(shape);
}
}

Here we have a List<T> shapes and a T shape, therefore we can safely shapes.add(shape). If it was declared List<? extends Shape>, you can NOT safely add to it (because you may have a List<Square> and a Circle).

So by giving a name to a bounded type parameter, we have the option to use it elsewhere in our generic method. This information is not always required, of course, so if you don't need to know that much about the type (e.g. your drawAll), then just wildcard is sufficient.

Even if you're not referring to the bounded type parameter again, a bounded type parameter is still required if you have multiple bounds. Here's a quote from Angelika Langer's Java Generics FAQs

What is the difference between a wildcard bound and a type parameter bound?

A wildcard can have only one bound, while a type parameter can have several bounds.
A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.

Wildcard bounds and type parameter bounds are often confused, because they are both called bounds and have in part similar syntax. […]

Syntax:

  type parameter bound     T extends Class & Interface1 & … & InterfaceN

wildcard bound
upper bound ? extends SuperType
lower bound ? super SubType

A wildcard can have only one bound, either a lower or an upper bound. A list of wildcard bounds is not permitted.

A type parameter, in constrast, can have several bounds, but there is no such thing as a lower bound for a type parameter.

Quotes from Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility:

For maximum flexibility, use wildcard types on input parameters that represent producers or consumers. […] PECS stands for producer-extends, consumer-super […]

Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code. Properly used, wildcard types are nearly invisible to users of a class. They cause methods to accept the parameters they should accept and reject those they should reject. If the user of the class has to think about wildcard types, there is probably something wrong with the class's API.

Applying the PECS principle, we can now go back to our addIfPretty example and make it more flexible by writing the following:

public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }

Now we can addIfPretty, say, a Circle, to a List<Object>. This is obviously typesafe, and yet our original declaration was not flexible enough to allow it.

Related questions

  • Java Generics: What is PECS?
  • Can someone explain what does <? super T> mean and when should it be used and how this construction should cooperate with <T> and <? extends T>?

Summary

  • Do use bounded type parameters/wildcards, they increase flexibility of your API
  • If the type requires several parameters, you have no choice but to use bounded type parameter
  • if the type requires a lowerbound, you have no choice but to use bounded wildcard
  • "Producers" have upperbounds, "consumers" have lowerbounds
  • Do not use wildcard in return types

Difference between Bounded Type parameter (T extends) and Upper Bound Wildcard (? extends)

There are several differences between the two syntaxes during compile time :

  • With the first syntax, you can add elements to someList but with the second, you can't. This is commonly known as PECS and less commonly known as the PUT and GET prinicple.
  • With the first syntax, you have a handle to the type parameter T so you can use it to do things such as define local variables within the method of type T, cast a reference to the type T, call methods that are available in the class represented by T, etc. But with the second syntax, you don't have a handle to the type so you can't do any of this.
  • The first method can actually be called from the second method to
    capture the wildcard. This is the most common way to capture a
    wildcard via a helper method.

    private static <T extends Number> void processList(List<T> someList) {
    T n = someList.get(0);
    someList.add(1,n); //addition allowed.
    }

    private static void processList2(List<? extends Number> someList) {
    Number n = someList.get(0);
    //someList.add(1,n);//Compilation error. Addition not allowed.
    processList(someList);//Helper method for capturing the wildcard
    }

Note that since generics are compile time sugar, these differences at a broader level are only limited to the compilation.

Generic Wildcard Bounded Type vs Generic Bounded Type Parameter

No difference in this case. For more complex signatures, you may need to reuse the defined type so defining it is needed. Something like:

public static <T extends Number> void foo(T bar, List<T> myList)...

This guarantees not only that both bar and the elements of myList extend Number, but they are of the same type. You could not positively enforce that with the other syntax.

What are the usage wildcard or Bounded type parameters in Java Generics?

In your example there is absolutely no benefit.

Consider the following method signature

public static <T extends Shape> void draw(List<T> shapes) { /* ... */ }

I can do the following

final List<Circle> circles = /* ... */
final List<Square> squares = /* ... */

draw(squares);
draw(circles);

Which I cannot do with

public static void draw(List<Shape> shapes) { /* ... */ }

This especially important with PECS type situations.

Difference between ? (wildcard) and Type Parameter in Java

They are the same in that they accept the same parameter types.

However, identifying the type with T (or whatever) lets you refer to the type elsewhere.

Edit: Examples:

Your unbounded examples do not make full use of the capabilities of parameterized types. You have:

public static <T> void printList(List<T> list) {
for (Object elem : list)
System.out.println(elem + " ");
System.out.println();
}

And that's sufficient for that example of printing string representations, but consider this (very contrived, and no error handling):

public static <T> T getSecondItem (List<T> list) {
T item = list.get(1);
return item;
}

The return type is T, which allows you to safely do things like this, with compile time type-checking:

class MyClass {
public void myMethod () { }
}

void somewhere () {
List<MyClass> items = ...;
getSecondItem(items).myMethod();
}

A named type also lets you share the same type constraint in multiple places, e.g.:

public <T> int compareLists (List<T> a, List<T> b) {
...
}

If you did not name the type, you could not specify the constraint that a and b are the same list type (you could use List<? extends T> for more flexibility).

You also asked "Why do I need ??". The real answer is: You don't. It's mostly for aesthetics, I suppose. Java strives to be a precise and clutter-free language. There are many situations where you simply don't care what type you are referring to. In those cases, you may use ? without cluttering code with unused type parameter declarations.

Difference between generic type and wildcard type

The first signature says: list1 is a List of Es.

The second signature says: list is a List of instances of some type, but we don't know the type.

The difference becomes obvious when we try to change the method so it takes a second argument, which should be added to the list inside the method:

import java.util.List;

public class Experiment {
public static <E> void funct1(final List<E> list1, final E something) {
list1.add(something);
}

public static void funct2(final List<?> list, final Object something) {
list.add(something); // does not compile
}
}

The first one works nicely. And you can't change the second argument into anything that will actually compile.

Actually I just found an even nicer demonstration of the difference:

public class Experiment {
public static <E> void funct1(final List<E> list) {
list.add(list.get(0));
}

public static void funct2(final List<?> list) {
list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!!
}
}

One might as why do we need <?> when it only restricts what we can do with it (as @Babu_Reddy_H did in the comments). I see the following benefits of the wildcard version:

  • The caller has to know less about the object he passes in. For example if I have a Map of Lists: Map<String, List<?>> I can pass its values to your function without specifying the type of the list elements. So

  • If I hand out objects parameterized like this I actively limit what people know about these objects and what they can do with it (as long as they stay away from unsafe casting).

These two make sense when I combine them: List<? extends T>. For example consider a method List<T> merge(List<? extends T>, List<? extends T>), which merges the two input lists to a new result list. Sure you could introduce two more type parameters, but why would you want to? It would be over specifying things.

  • finally wildcards can have lower bounds, so with lists you can make the add method work, while get doesn't give you anything useful. Of course that triggers the next question: why don't generics have lower bounds?

For a more in depth answer see: When to use generic methods and when to use wild-card? and http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203

Java generics: wildcard? vs type parameterE?

Your approach of using a generic method is strictly more powerful than a version with wildcards, so yes, your approach is possible, too. However, the tutorial does not state that using a wildcard is the only possible solution, so the tutorial is also correct.

What you gain with the wildcard in comparison to the generic method: You have to write less and the interface is "cleaner" since a non generic method is easier to grasp.

Why the generic method is more powerful than the wildcard method: You give the parameter a name which you can reference. For example, consider a method that removes the first element of a list and adds it to the back of the list. With generic parameters, we can do the following:

static <T> boolean rotateOneElement(List<T> l){
return l.add(l.remove(0));
}

with a wildcard, this is not possible since l.remove(0) would return capture-1-of-?, but l.add would require capture-2-of-?. I.e., the compiler is not able to deduce that the result of remove is the same type that add expects. This is contrary to the first example where the compiler can deduce that both is the same type T. This code would not compile:

static boolean rotateOneElement(List<?> l){
return l.add(l.remove(0)); //ERROR!
}

So, what can you do if you want to have a rotateOneElement method with a wildcard, since it is easier to use than the generic solution? The answer is simple: Let the wildcard method call the generic one, then it works:

// Private implementation
private static <T> boolean rotateOneElementImpl(List<T> l){
return l.add(l.remove(0));
}

//Public interface
static void rotateOneElement(List<?> l){
rotateOneElementImpl(l);
}

The standard library uses this trick in a number of places. One of them is, IIRC, Collections.java

Difference between generic types and wildcards extending a type for parameters to a method

What you wrote is invalid syntax. This is what you intended:

public static <T extends Number> double foo(List<T> list) {

That is, the extends belongs to the type token definition, not the type declaration in the method parameter list.



Related Topics



Leave a reply



Submit