marcius.tan
marcius.tan

Reputation: 97

Java Generic on method with Functional Interface parameter type

I cannot figure out why this code don't compile :

package Desktop;

import java.util.function.*;

public class MyClass {

    public static <T, U> Long myMethod( Function<T, U> methodParam ) {
      return methodParam.apply("Today is happy day!");
    }

   public static void main(String[] args) {
      System.out.println( <String, Long>myMethod( Long::valueOf ) );
   }

}

So i receive this on console:

..\Desktop\MyClass.java:15: error: illegal start of expression
          System.out.println( <String, Long>myMethod( Long::valueOf ) );
                                            ^
..\Desktop\MyClass.java:15: error: ';' expected
          System.out.println( <String, Long>myMethod( Long::valueOf ) );
                                                                     ^
2 errors

I am expecting to use generics to include type for the lambda on method parameter.

Upvotes: 0

Views: 1290

Answers (3)

Sree Kumar
Sree Kumar

Reputation: 2245

The reason is that Long.valueOf() takes only either String or long. From the type parameter T, the compiler concludes that the Function takes Object, it will not allow it since there is no method as Long.valueOf( Object ).

You may have to change myMethod() to this signature:

public static <T, U> Long myMethod( Function<String, Long> methodParam ) { //Both type parameters are explicit
    return methodParam.apply("Today is happy day!");
}

Or this, which may throw NumberFormatException:

public static <T, U> Long myMethod( Function<String, U> methodParam ){ //Input  type parameter is explicit
    return (Long) methodParam.apply( "Today is happy day!" );
}

Upvotes: 1

Matthias Heinlein
Matthias Heinlein

Reputation: 55

As Eran's answer suggests, you have 2 problems: In the definition of myMethod and in the call of the method.

1) You declare methodParam as a function with input type T and output type U. And then in myMethod you treat it as if T was String and U was Long. This is only how you want to call the method but the compiler does not know anything about T and U at this point. Erans solution for myMethod works as myMethod returns a value of type U (instead of Long) and receives a parameter of type T instead of calling apply() with a string.

2) The call of myMethod() in the main method: either as in Erans example the type parameters are implicitly given by your parameters. Otherwise, if you need to express them explicitly for some reason, @ernest_k showed the solution (also found here).

Upvotes: 1

Eran
Eran

Reputation: 393811

It should be:

public static <T, U> U myMethod(Function<T, U> methodParam, T t) {
  return methodParam.apply(t);
}

public static void main(String[] args) {
   System.out.println(myMethod(Long::valueOf, "Today is happy day!") );
}

myMethod accepts a Function with generic parameters, so you can't always call its apply method with a String argument and expect it to return a Long.

Instead, you can pass to it the String argument, and change its return type to U.

Of course, this code will throw a NumberFormatException, since you can't convert that String to a Long.

Upvotes: 5

Related Questions