views:

180

answers:

4

A Java method call may be parameterized like in the following code:

class Test
{
    <T> void test()
    {
    }

    public static void main(String[] args)
    {
        new Test().<Object>test();
        //         ^^^^^^^^
    }
}

I found out this is possible from the Eclipse Java Formatter settings dialog and wondered if there are any cases where this is useful or required.


EDIT

Based on Arne's excellent answer i came up with the following conclusion:

In addition to improved type safety as Arne's example illustrates a parameterized method call enables you to specify the common base type of the methods arguments that should be the type of the container elements. This type is normally inferenced automatically by the compiler to the most specific common base type. By parameterizing the method call this behaviour may be overridden. A parameterized method call may be required if there are multiple common types inferenced by the compiler.

The following example demonstrates that behaviour:

import java.util.Arrays;
import java.util.List;

class Test
{
    public static void main(String[] args)
    {
        Integer a=new Integer(0);
        Long    b=new Long(0);
        List<Object> listError=Arrays.asList(a, b);
        //error because Number&Comparable<?> is not Object
        List<Object> listObj=Arrays.<Object>asList(a, b);
        List<Number> listNum=Arrays.<Number>asList(a, b);
        List<Comparable<?>> listCmp=Arrays.<Comparable<?>>asList(a, b);
    }
}

This behaviour is defined in The Java Language Specification Third Edition paragraphs 8.4.4 and 15.12.2.7 but not easily understood.

+3  A: 

It is probably most useful when you are taking a collection of some type, and returning some subset of that collection.

<T> List<T> filter(Collection<? extends T> coll, Predicate<? super T> pred) {
    List<T> returnList = new ArrayList<T>();
    for(T t : coll) {
        if(pred.matches(t)){
            returnList.add(t);
        }
    }
    return returnList;
}

Edit:

More generally, it is useful whenever you wish to return a specific type, or you want to link the types of two or more parameters in a general way.

ILMTitan
you're not doing a parameterized method call anywhere in that code
newacct
+7  A: 

Parameterized method calls are useful when you want to allow different types without casting. For example, the Collections helper class makes extensive use of parameterized method calls. When you want to make a new generic collection using one of their helper methods, a few examples:

List<String> anEmptyStringList = Collections.<String>emptyList();
Set<Integer> unmodifiableCopy = Collections.<Integer>unmodifiableSet(originalSet);

So, when you want to be able to use the generic type elsewhere, you want to use those method calls. They prevent compiler warnings when using generics.

justkt
Isn't the collection type inferred from the variable declaration anyway?
You will get a cast warning from the compiler (unless you've turned them off) if you do `List<String> anEmptyStringList = Collections.emptyList()` without the parameter in the call. In fact, I first learned about this from a colleague who was showing me how to get rid of the warning.
justkt
I can not reproduce that warning on my setup. Not even with the -Xlint parameter. That is probably caused by compiler differences. I use javac 1.6.0_20 from the Sun JDK on Linux.
I'm pretty sure the compiler will never produce this warning what calling the 'emptyList' this way. I have enabled the warnings for generics and do not get a warning.
Arne
@Arne - it's been a while since I didn't call it with the parameter, but I know that I got some sort of error that was bugging my colleague. There is a possibility it was static code analysis. I can't check on this for several hours, but I will try later.
justkt
I'm stumped. I can't get the error either after several tries, but I know I've seen it before.
justkt
A: 

For example, when you need some universal method for comparisons:

public static <T extends Comparable> T max(T one, T two) {
    if (one.compareTo(two) > 0) {
        return one;
    } else {
        return two;
    }
}
Aleksejs
Assuming the method is a member of class Aggregator and the generic type parameter T is added to Comparable in the declaration then i can call it simply asAggregator.max(new Integer(5), new Integer(10));No parameters required on the call.
you're not doing a parameterized method call anywhere in that code
newacct
Yep, agree. No need to additionally specify class.
Aleksejs
+1  A: 

I never have used this in practice, but you can imagine to use this for type safety. Consider the following method:

<T> void method(T... items) {
    List<T> list = new ArrayList<T>();
    for (T item : items)
        list.add(item);
    System.out.println(list);
}

You can call it this way:

o.<Object>method("Blah", new Long(0));
o.<Number>method(new Integer(100), new Long(0));

But this will raise an compiler error:

o.<Number>method("String", new Long(0));

So you have an generic method that is typesafe and can be used for every Object, not limited to a paricular interface or class.

Arne
excellent answer especially the use of varargs