Set<String> premiumStrings = new HashSet<>();
Set<String> sortedSet = new TreeSet<>(Comparator.comparing(premiumStrings::contains).thenComparing(Comparator.naturalOrder()));
This doesn't work, because premiumStrings::contains
can take any object and not just strings. One can replace it with (String s) -> premiumStrings.contains(s)
, but is there a way to restrict the parameter type while still using a method reference lambda?
(Specifically, the problem is The method thenComparing(Comparator<? super Object>) in the type Comparator<Object> is not applicable for the arguments (Comparator<Comparable<? super Comparable<? super T>>>)
.)
CodePudding user response:
Help the compiler a bit with types:
Set<String> sortedSet = new TreeSet<>(
Comparator.<String, Boolean>comparing(premiumStrings::contains).thenComparing(Comparator.naturalOrder()));
CodePudding user response:
The compiler should infer the types of arguments passed to each method.
And when we have a chain of methods, the context doesn't provide enough information for that. And the argument of every method reference (or lambda expression) would be treated as being of type Object
and not String
.
To avoid that, we can provide the type explicitly as a parameter of a lambda expression:
Set<String> premiumStrings = new HashSet<>();
Comparator<String> comparator =
Comparator.comparing((String str) -> premiumStrings.contains(str))
.thenComparing(Comparator.naturalOrder());
Set<String> sortedSet = new TreeSet<>(comparator);
Or by using so-called Type Witness: Comparator.<String>comparing().thenComparing()
.
For more information, see.