javagenericsopenjdk-11static-factory

JDK 11 Generics Issue when using Set.of


I am unable to understand the below issue for type safety when using JDK 11. Can anyone explain the reason for not getting a compilation error when I am directly passing the Set.of in the argument:

public static void main(String[] args) {
    var intSet1 = Set.of(123, 1234, 101);
    var strValue = "123";
    isValid(strValue, intSet1);// Compilation error (Expected behaviour)
    **isValid(strValue, Set.of(123, 1234, 101));// No Compilation error**
}

static <T> boolean isValid(T value, Set<T> range) {
    return range.contains(value);
}

You can run this code live at IdeOne.com.


Solution

  • To put it simply, the compiler is stuck with your declared types on the first call, but has some latitude to infer a compatible type on the second one.

    With isValid(strValue, intSet1);, you're calling isValid(String, Set<Integer>), and the compiler does not resolve T to the same type for the two arguments. This is why it's failing. The compiler simply can't change your declared types.

    With isValid(strValue, Set.of(123, 1234, 101)), though, Set.of(123, 1234, 101) is a poly expression, whose type is established in the invocation context. So the compiler works at inferring T that is applicable in context. As Eran points out, this is Serializable.

    Why does the first one work and the second one doesn't? It's simply because the compiler has some flexibility around the type of the expression given as the second argument. intSet1 is a standalone expression, and Set.of(123, 1234, 101) is a poly expression (see the JLS and this description about poly expression) . In the second case, the context allows the compiler to compute a type that works to a concrete T that is compatible with String, the first argument's type.