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.
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 callingisValid(String, Set<Integer>)
, and the compiler does not resolveT
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 inferringT
that is applicable in context. As Eran points out, this isSerializable
.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, andSet.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 concreteT
that is compatible withString
, the first argument's type.