23

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.

  • Is it only me that thinks it's weird how everybody in this thread seems to think a "parameterized method" must be a generic method? A method that has parameters declared is a "parameterized" method. A generic method is just another parameterized method where the type is one such parameter. Or have I missed something? – Martin Andersson Sep 22 '17 at 13:24
  • You are spot on! In hindsight the title should probably have been "When is a method call with type arguments that can not possibly be inferred useful?" – Johann-Christoph Jacob Sep 23 '17 at 16:51

4 Answers4

22

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 Deutsch
  • 14,629
  • 5
  • 53
  • 72
14

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
  • 14,610
  • 8
  • 42
  • 62
  • 3
    Isn't the collection type inferred from the variable declaration anyway? – Johann-Christoph Jacob May 06 '10 at 14:32
  • You will get a cast warning from the compiler (unless you've turned them off) if you do `List 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 May 06 '10 at 14:35
  • 1
    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. – Johann-Christoph Jacob May 06 '10 at 15:02
  • 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 Deutsch May 06 '10 at 15:06
  • @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 May 06 '10 at 15:26
  • I'm stumped. I can't get the error either after several tries, but I know I've seen it before. – justkt May 06 '10 at 23:44
  • also worth noting, in a method of return type e.g. `List`, `return collections.emptyList()` is valid because the compiler knows the type you want to return but it gets lost in `return list != null ? list : Collections.emptyList();` which doesn't compile. However using a parameterized call fixes this without casting and still using an inline statement `return list != null ? list : Collections.emptyList();` – user1084563 Mar 19 '13 at 00:11
  • 1
    Please note that [the issue](https://bugs.openjdk.java.net/browse/JDK-6721089) @user1084563 refers to is fixed with Java 8 (confirmed with openjdk-8-jdk-headless_8u111-b14-2~bpo8+1_amd64.deb and zulu8.19.0.1-jdk8.0.112-win_x64.zip). – Johann-Christoph Jacob Jan 18 '17 at 20:50
  • @Johann-ChristophJacob sometimes we just need to pass the result to a method, and the type is not inferred from the parameter declaration... – marcolopes Jun 02 '18 at 03:46
  • @marcolopes please elaborate on that with an example. – Johann-Christoph Jacob Jun 04 '18 at 18:20
11

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
  • 10,751
  • 3
  • 30
  • 46
1

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 Mjaliks
  • 8,647
  • 6
  • 38
  • 44