Type Argument Inference by Parameter List

This section provides a tutorial example on type argument inference by parameter list. The compiler will deduce the type argument by looking at actual arguments for the method parameter list if the type parameter is used there.

Type argument inference (also called type inference) on generic method invocation is something I will not recommend. But if you want to use it, you can gain some experience with the following tutorial example:

/* TypeInferenceByParameter.java
 - Copyright (c) 2014, HerongYang.com, All Rights Reserved.
 */
class TypeInferenceByParameter {
   public static <T extends Comparable<T>> T maxGeneric(T a, T b) {
      if (a.compareTo(b)>=0) {
         return a;
      } else {
      	 return b;
      }
   }
   public static void main(String[] a) {
      String as = "1234";
      String bs = "789";
      Integer ai = new Integer(1234);
      Long bl = new Long(789L);

      /* Test 1 - Type argument specified as String */
      String ms 
         = TypeInferenceByParameter.<String>maxGeneric(as, bs);
      System.out.println("Maximum: "+ms);

      /* Test 2 - Type argument inferred to String
                  by looking at parameters as and bs
      Object os = TypeInferenceByParameter.maxGeneric(as, bs);
      System.out.println("Maximum: "+os);
      */

      /* Test 3 - Type argument inference failed
                  to deduce to a single type
      Long ml = TypeInferenceByParameter.maxGeneric(ai, bl);
      System.out.println("Maximum: "+ml);
      */

      /* Test 4 - Type argument inference failed
                  to deduce to a subtype of Comparable
      Integer mi = TypeInferenceByParameter.maxGeneric(
         (Number)ai, (Number)bl);
      System.out.println("Maximum: "+mi);
      */

      /* Test 5 - Type argument inferred to Short
                  but runtime exception occurred
      Number mn = TypeInferenceByParameter.maxGeneric(
         (Short)(Number)ai, (Short)(Number)bl);
      System.out.println("Maximum: "+mn);
      */
   }
}

On test 1, I was not using type argument inference. So there was no compilation error and runtime exception. The execution result was correct:

Maximum: 789

On test 2, I let the compiler to do the type inference. The compiler did a good job to deduce the type argument to be "String" and the result was correct:

Maximum: 789
Maximum: 789

On test 3, I purposely provided inconsistent types in the argument list "ai, bl". The JDK 1.7 compiler failed on the type inference process and gives me this compilation error. The error message said that the inferred type was INT#1 and did not conform to the declared bound. But I see the root cause is that found types "Integer,Long" does not match required types "T,T" where both of types must be the same type:

TypeInferenceByParameter.java:31: error: method maxGeneric in class 
TypeInferenceByParameter cannot be applied to given types;
      Long ml = TypeInferenceByParameter.maxGeneric(ai, bl);
                                        ^
  required: T,T
  found: Integer,Long
  reason: inferred type does not conform to declared bound(s)
    inferred: INT#1
    bound(s): Comparable<INT#1>
  where T is a type-variable:
    T extends Comparable<T> declared in method <T>maxGeneric(T,T)
  where INT#1,INT#2 are intersection types:
    INT#1 extends Number,Comparable<? extends INT#2>
    INT#2 extends Number,Comparable<?>

In the JDK 1.8, the compilation error message on test 3 is better:

TypeInferenceByParameter.java:31: error: method maxGeneric in class 
   TypeInferenceByParameter cannot be applied to given types;
      Long ml = TypeInferenceByParameter.maxGeneric(ai, bl);
                                        ^
  required: T,T
  found: Integer,Long
  reason: inference variable T has incompatible bounds
    equality constraints: Integer,Long
    lower bounds: Long,Integer
  where T is a type-variable:
    T extends Comparable<T> declared in method <T>maxGeneric(T,T)
1 error

On test 4, I did provide the consistent types "Number,Number". But "Number" is not a subtype of "Comparable". So the compiler failed again with the appropriate message saying that inferred type is "Number" and does not conform to the declared bound.

TypeInferenceByParameter.java:37: error: method maxGeneric in class 
   TypeInferenceByParameter cannot be applied to given types;
      Integer mi = TypeInferenceByParameter.maxGeneric(
                                           ^
  required: T,T
  found: Number,Number
  reason: inferred type does not conform to upper bound(s)
    inferred: Number
    upper bound(s): Comparable<Number>
  where T is a type-variable:
    T extends Comparable<T> declared in method <T>maxGeneric(T,T)
1 error

On test 5, I double-casted both parameter objects to be the same type "Short". The compiler was stupid and deduced the type argument to be "Short" with no errors. But the runtime caught the type casting issue and gave a "ClassCastException".

Maximum: 789
Exception in thread "main" java.lang.ClassCastException: 
java.lang.Integer cannot be cast to java.lang.Short
   at TypeInferenceByParameter.main(TypeInferenceByParameter.java:44)

I think we have done enough testing with type argument inference with the method parameter list. We will test type argument inference with the method return value in the next section.

Last update: 2014.

Table of Contents

 About This Book

 Installing JDK 1.8 on Windows

 Execution Process, Entry Point, Input and Output

 Primitive Data Types and Literals

 Bits, Bytes, Bitwise and Shift Operations

 Managing Bit Strings in Byte Arrays

 Reference Data Types and Variables

 StringBuffer - The String Buffer Class

 System Properties and Runtime Object Methods

 Generic Classes and Parameterized Types

Generic Methods and Type Inference

 What Is a Generic Method?

 Comparing Generic Method with Non-Generic Method

 Non-Generic Method Example - maxNonGeneric()

 Generic Method Example - maxGeneric()

 Generic Methods in java.util.Collections Class

 Testing Generic Methods in Collections Class

 What Is Type Argument Inference?

Type Argument Inference by Parameter List

 Type Argument Inference by Return Value

 Generic Methods using Parameterized Types

 Parameterized Type as Generic Method Return Type

 Lambda Expressions and Method References

 Execution Threads and Multi-Threading Java Programs

 ThreadGroup Class and "system" ThreadGroup Tree

 Synchronization Technique and Synchronized Code Blocks

 Deadlock Condition Example Programs

 Garbage Collection and the gc() Method

 Outdated Tutorials

 References

 PDF Printing Version