Search code examples
javagenericsgeneric-method

Generic methods with no extra information on Parameter


As far as I can tell, this is a generic method (as opposed to a method of a generic class):

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
        Function<? super T, ? extends U> keyExtractor)

I'm curious how Java decides the parameter types for any keyExtractor lambda that I pass in, given that T is parameterized.

If there was some extra information, like if T was restricted to being T super Z for some concrete Z, then it would make sense that you can only pass in subclasses of Z, and thus inside the keyExtractor lambda I can typecheck as if a class Z object has been passed in.

But given that there's no information available on T, how does this even work? Does it decide based on the context of how the lambda being returned by comparing is being used? I'm very confused, but maybe I don't fully understand generics and lambdas.

Any clarification would be appreciated, thanks!


Solution

  • But given that there's no information available on T, how does this even work?

    If there really is no information available on T, then it defaults to Object, such as when you call comparing as a standalone statement:

    Comparator.comparing(x -> { ... });
    

    The compile time type of x will be Object.

    But you rarely call comparing like that, right? You usually pass its return value into method, or at least assign it to a variable of a known type first:

    someMethod(Comparator.comparing(x -> { ... }));
    // or
    Comparator<SomeType> c = Comparator.comparing(x -> { ... });
    

    In both of these situations, there are more information to determine what T is. Notice that the return type of comparing is Comparator<T>, so if someMethod above accepts a Comparator<SomeType>, the type inference engine can work out that T must be SomeType in both cases.

    Also note that you can specify the parameter's type in a lambda, this helps infer T as well:

    Comparator.comparing((SomeType x) -> { ... })