2

The first assignment below doesn't compile, but I am not sure why, the method signature of the static method matches the functional method signature albeit it is not using type arguments. The second line compiles fine even though it is the same signature except for the type parameterization.

What is the reasoning behind this?

public class GenericSample<T> {
    public static void staticLambdaMtd(Integer a) {
            
    }   

    public static<X> void staticLambdaMtd2(X a) {
            
    }  

    // Funca<T> fa1 = GenericSample::staticLambdaMtd;//does not compile !

    Funca<T> fa = GenericSample::staticLambdaMtd2;//does compile !      
}
    
interface Funca<A> {
    public void funct(A a);
}
1
  • 2
    The variable fa1 should be of type Funca<Integer> for the first expression to compile. The compiler would expect a function having generic type T on the right side of the expression (some type that would be defined while class GenericSample will get instantiated), but you're trying to utilize a method reference that is capable to work only with Integer type (not with an arbitrary type). Therefore, the compiler will disallow this assignment. Commented May 18, 2022 at 22:30

1 Answer 1

6

You are mixing a generic parameter T and a type Integer. That wouldn't work because T and Integer are different types.

Generics are invariant. That means you can assign to a List<Person> only another list having the same generic parameter, i.e. Person (not Integer, Cat or T). Similarly, we can't assign Funca<Integer> to a variable of type Funca<T>.

For more information, have a look at this tutorial provided by Oracle.

A function created using a static method staticLambdaMtd(Integer a) is assignable only to a variable of type Funca<Integer>, but not Funca<T> - i.e. function of some arbitrary type, because only Integer type would match the method signature, but not any type (like String, Cat, BigDecimal) that would be defined while class GenericSample will get instantiated.

The second statement compiles fine, because it doesn't expect any specific type. X is only a placeholder, as well as T. And expression GenericSample::staticLambdaMtd2 should be classified as a so-called poly expression, i.e. because you're not providing a type compiler needs to infer it from the assignment context.

Therefore, the expression GenericSample::staticLambdaMtd2 would be inferred as being of type Funca<T> and the second statement will compile fine.

All assignments shown below are valid:

// expression on the right could represent only `Funca<Integer>`

Funca<Integer> fa1 = GenericSample::staticLambdaMtd;


// expression on the right can be succefully inferred to 
// a function of any type based on the assingment context on the left

Funca<T> fa = GenericSample::staticLambdaMtd2;      
Funca<String> fa = GenericSample::staticLambdaMtd2;
Funca<BigDecimal> fa = GenericSample::staticLambdaMtd2;

Note that expression GenericSample::staticLambdaMtd2 can be turned from a poly expression into a "standalone form" by providing a generic parameter (in fact, method references by definition provided in the specification are always poly expressions, therefore I've used "standalone" in quotation marks meaning only that assignment context will be ignored).

And that we how can break it:

// that will not compile for the same reason as the the firt statement doesn't compile

Funca<T> fa3 = GenericSample::<Integer>staticLambdaMtd2;
Sign up to request clarification or add additional context in comments.

3 Comments

@Holger BTW I was expecting that someone propose a better explanation when a method reference is being provided with an explicit generic parameter Type::<Something>method. According to the specification, method references are always poly expressions, but in this case there's nothing to infer, the compiler still has to check where the provided parameter matches the method signature and whether the reference fits in to the context. In this case, everything will seem to work like in Java 7, where there were no poly expressions (sure, and no method references as well).
@Holger Why method reference with an explicit type argument still should be treated as poly expression?
It seems, you wrote @Holger after my comments were removed, so I didn’t get a notification. • A method reference is an expression which always evaluates to some instance of a functional interface. Since this result interface type is always given as target type, in other words, a method reference has no type of its own, a method reference is always a poly expression.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.