Thanks for the comment Elliott. The reason I assigned the method reference to a variable of type IntUnaryOperator is that it is an exact match to the signature of the method (staticFunction_arg_int_return_int) which is int -> int. I wasn't looking to fix it, just presenting it as a data point about how Java works. But your alternative assignment offers another datapoint, and it's a very valuable one.
If I add this code (C) to main:
/* (C) genericForSpecializedFunction - works - stacktrace:
*
Thread [main] (Suspended (breakpoint at line 15 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_int_return_int(int) line: 15
575593575.apply(Object) line: not available <- lambda
CompilerGeneratedLambdaExample.callFunction(Function<A,R>, A) line: 10
CompilerGeneratedLambdaExample.main(String[]) line: 67
Output:
genericForSpecializedFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$2/575593575@14acaea5 <- same lambda
(C) value type: java.lang.Integer
(C) value: 10
*/
Function<Integer,Integer> genericForSpecializedFunction = CompilerGeneratedLambdaExample::staticFunction_arg_int_return_int; // OK
System.out.println("genericForSpecializedFunction: " + genericForSpecializedFunction);
Object value3 = callFunction(genericForSpecializedFunction,new Integer(10));
System.out.println("(C) value type: " + value3.getClass().getName());
System.out.println("(C) value: " + value3)
I see that the static method staticFunction_arg_int_return_int is wrapped in a lambda just as it is when passed directly to callFunction. In effect, the same conversion, if you want to call it that, is happening in both cases.
Further, if I add code (D) similar to(C), only with a static method that directly matches a non-specialized type:
<code>
static Integer staticFunction_arg_Integer_return_Integer(Integer i) {
return i;
}
...
/* (D) with generic methods - stack
*
Thread [main] (Suspended (breakpoint at line 19 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_Integer_return_Integer(Integer) line: 19
226710952.apply(Object) line: not available <- lambda
CompilerGeneratedLambdaExample.callFunction(Function<A,R>, A) line: 10
CompilerGeneratedLambdaExample.main(String[]) line: 84
Output:
genericFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$3/226710952@59fa1d9b <- same lambda
(D) value type: java.lang.Integer
(D) value: 10
*/
Function<Integer,Integer> genericFunction = CompilerGeneratedLambdaExample::staticFunction_arg_Integer_return_Integer; // OK
System.out.println("genericFunction: " + genericFunction);
Object value4 = callFunction(genericFunction,new Integer(10));
System.out.println("(D) value type: " + value4.getClass().getName());
System.out.println("(D) value: " + value4);
</code>
I see the exact same behavior as (C), even through no argument or return value conversions are needed.
And finally, if I add code (E) reversing the scenario by assigning a generic function to a specialized type:
<code>
static int callIntUnaryOperator(IntUnaryOperator function, int arg) {
return function.applyAsInt(arg);
}
...
/* (E) specialiedForGenericFunction - stack
*
Thread [main] (Suspended (breakpoint at line 24 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_Integer_return_Integer(Integer) line: 24
684874119.applyAsInt(int) line: not available <- lambda
CompilerGeneratedLambdaExample.callIntUnaryOperator(IntUnaryOperator, int) line: 15
CompilerGeneratedLambdaExample.main(String[]) line: 109
output:
specializedForgenericFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$4/684874119@4501b7af <- same lambda
*/
IntUnaryOperator specializedForGenericFunction = CompilerGeneratedLambdaExample::staticFunction_arg_Integer_return_Integer; // OK
System.out.println("specializedForgenericFunction: " + specializedForGenericFunction);
int value5 = callIntUnaryOperator(specializedForGenericFunction,10);
//System.out.println("(E) value type: " + value5.getClass().getName());
System.out.println("(E) value: " + value5);
</code>
everything works just as in (C) and (D).
My interpretation of all of this is that:
(1) The functional type of a method reference is not intrinsic to the method reference and is not fully determined by the referenced method (plus or minus class instance for non-static methods). The functional type becomes fixed only when the method reference is assigned to a variable or function parameter or return value with a functional type that is compatible with the type of the referenced method (plus or minus instance). The functional type in question is termed the target type, if I understand correctly.
(2) An important case where the target type is compatible with the type of the referenced method (plus or minus instance) without being the same is that where some argument(s) and/or return value differ in type between primitive (unboxed, specialized) and corresponding object (instantiated generic, boxed).
(3) In this context there is no privileging of object (generic) over primitive (specialized) types. Their relationship is symmetrical, so that the underlying method may have, say, a primitive arg and the functional type an object arg or vice versa, and similarly for the return value. This means that boxing and unboxing can go either way.
(4) I originally thought of the lambdas that appear in the stacktraces and printed functional object values in the example code as wrappers around the underlying methods that exist to perform argument and return value type conversions (particularly boxing and unboxing), but I now see them as simply the concrete realizations of the functional types of the method references as determined by the types of the variables, function parameters or return types that they are being assigned to - the target types. These concrete realizations will always be created and will perform conversions (boxing and unboxing) only as an occasional side effect. Practically speaking, method reference are source code entities that are compiled into lambda objects just as source code lambda expressions are.
I will look at the doc section you link to paying particular attention to references to target types and method references.