The way
Java performs type inference on lambda expressions is very complex and will take a long time to explain. The short answer is that in the first case, you explicitly told the compiler to use the
length() method of the
String class, while in the second case, the compiler has to infer that you want to use the
String class. Part of the reason why the compiler is not able to infer that you want to use
String, is because
comparing() takes a generic type with a parameter that has a lower bound. So when you write
Comparator.comparing(s -> s.length()), the compiler interprets that as
Comparator.comparing((Object s) -> s.length()). As you know,
Object doesn't have a
length() method. The compiler does not look at the surrounding method call to provide the
comparing() method with more context.
You can fix this by explicitly stating the type of the lambda argument, or by passing the generic type arguments to the
comparing() method explicitly: