Below are the two lines of my code snippet:
List<String> listDevs = Arrays.asList("alvin", "Alchemist", "brutus", "larsen", "jason", "Kevin");
listDevs.sort(Comparator.comparing(String::length)); //This works fine
listDevs.sort(String::compareToIgnoreCase); //This works fine
But (out of expermient) when I try to write
listDevs.sort(Comparator.comparing(String::compareToIgnoreCase));
The compiler throws error
Cannot make a static reference to the non-static method compareToIgnoreCase(String) from the type String
Similar happens to the below code
listDevs.sort(Comparator.comparing(String::compareTo));
I understand the error and that it works fine if I remove the Comparator.comparing (as shown above).
But my point is, how does this line works?
listDevs.sort(Comparator.comparing(String::length));
I believe I am missing something. I have read this thread. Is this the same scenario?
The sort
method expected a Comparator
.
When you do this, you are indeed providing one.
listDevs.sort(Comparator.comparing(String::length));
Same happens here(but a bit non-intuitive):
listDevs.sort(String::compareToIgnoreCase)
listDevs.sort((left, right) -> left.compareToIgnoreCase(right)); // same thing as above
That's exactly the definition of a Comparator
- take two Strings and return an int.
The line that you say how come this works: listDevs.sort(Comparator.comparing(String::length));
is actually pretty simple.
Comparator.comparing
takes a Function
that transforms your input type into something that is Comparable
. In your case takes a String
and returns an Integer
; which is Comparable.
JLS says Compile-Time Declaration of a Method Reference of ReferenceType :: [TypeArguments] Identifier can be interpreted in different ways.
Given a targeted function type with n parameters, a set of potentially applicable methods is identified:
ReferenceType :: [TypeArguments] Identifier has two different arities, n and n-1, are considered, to account for the possibility that this form refers to either a static method or an instance method.
A method reference expression of the form ReferenceType :: [TypeArguments] Identifier can be interpreted in different ways. If Identifier refers to an instance method, then the implicit lambda expression has an extra parameter with type of this compared to if Identifier refers to a static method. It is possible for ReferenceType to have both kinds of applicable methods, so the search algorithm described above identifies them separately, since there are different parameter types for each case.
Comparator.comparing method accept a Function<T,R extends Comparable<? super R>>. when you use String::compareToIgnoreCase
that will reports error,because it has two parameters one is implicit this another is a comparing string of method parameter, so it is more like a BiFunction<String,String,Integer>
not a Function<String,Integer>
.
BiFunction<String, String, Integer> comparator = String::compareToIgnoreCase;
// you can't assign a BiFunction to a Function
// because one is incompatiable with another.
Function<String,Integer> function = comparator;
Stream.sort method accept a Comparator, and Comparator is more like a BiFunction<T,T,Integer>
so it is compatiable with String::compareToIgnoreCase
. on the other hand, they can be interchangeable. for example:
Comparator<String> primary = String::compareToIgnoreCase;
BiFunction<String, String, Integer> comparator1 = primary::compare;
Comparator<String> comparator2 = comparator1::apply;
you can using comparing(String::toLowerCase)
instead, it is equalivent to String::compareToIgnoreCase
, for example:
// String::compareToIgnoreCase
listDevs.sort(String::compareToIgnoreCase);
// comparing(String::toLowerCase)
listDevs.sort(comparing(String::toLowerCase))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With