Comparator.comparing (...) throws a non-static link exception when using String :: compareTo

The following are 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 (from experiment) when I try to write

 listDevs.sort(Comparator.comparing(String::compareToIgnoreCase)); 

The compiler gives an error

It is not possible to make a static reference to the non-static method compareToIgnoreCase (String) of type String

The same thing happens with the code below

 listDevs.sort(Comparator.comparing(String::compareTo)); 

I understand the error and works fine if I remove Comparator.comparing (as shown above).

But I want to say how this line works?

listDevs .sort (Comparator.comparing (String :: length));

I think something is missing. I read this thread. Is this the same scenario?

+5
source share
3 answers

Comparator.comparing expects a Function that describes a comparable property of elements. Thus, String::length sufficient since length() is a String property evaluating a String as int (which is why comparingInt is preferable here).

In contrast, String.compareToIgnoreCase and String.compareTo are comparison methods. They compare two String objects. Therefore, references to them are sufficient where Comparator is expected, but not where Function is expected.

How do you have a factory saying “Give me the engine and we will build a car for you” and you try to give them a full car. Although this existing car is valid where the car is expected, it makes no sense to transfer it to the factory to build the car.

Unfortunately, the current compiler implementation is very bad at reporting an error with functional signatures. You will almost always see messages such as "It is impossible to make a static link to a non-static method ..." when the signatures do not match.

+10
source

The expected method is sort a Comparator .

When you do this, you really provide it.

  listDevs.sort(Comparator.comparing(String::length)); 

The same thing happens here (but a little unintuitively):

  listDevs.sort(String::compareToIgnoreCase) listDevs.sort((left, right) -> left.compareToIgnoreCase(right)); // same thing as above 

The exact definition of a Comparator is to take two lines and return an int.

The line you are talking about is how it works: listDevs.sort(Comparator.comparing(String::length)); actually quite simple.

Comparator.comparing accepts a Function that converts your input type to something that is Comparable . In your case, takes a String and returns Integer ; which is comparable.

+5
source

JLS talks about compiling time to reference the ReferenceType :: [TypeArguments] method. Identifiers can be interpreted in different ways.

For the target function type with n parameters, a set of potentially applicable methods is determined:

ReferenceType :: [TypeArguments] The identifier has two different categories: n and n-1, which take into account the possibility that this form refers to either a static method or an instance method.

Expression for a reference expression of the form ReferenceType :: [TypeArguments] The identifier can be interpreted in different ways. If the Identifier refers to the instance method, then the implicit lambda expression has an additional parameter of type this compared to if the Identifier refers to the static method. Both types of applicable methods can be used for ReferenceType, therefore, the search algorithm described above identifies them separately, since for each case there are different types of parameters.

Comparator.comparing method accept Function <T, R extends Comparable <? →> . when you use String::compareToIgnoreCase , which will report an error because it has two parameters, one implicit this other is a method parameter comparison string , so it looks more like 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 Comparator , and Comparator is more like BiFunction<T,T,Integer> , therefore it is compatible with String::compareToIgnoreCase . on the other hand, they can be used interchangeably. eg:

 Comparator<String> primary = String::compareToIgnoreCase; BiFunction<String, String, Integer> comparator1 = primary::compare; Comparator<String> comparator2 = comparator1::apply; 

you can use comparing(String::toLowerCase) instead, it is equivalent to String::compareToIgnoreCase , for example:

 // String::compareToIgnoreCase listDevs.sort(String::compareToIgnoreCase); // comparing(String::toLowerCase) listDevs.sort(comparing(String::toLowerCase)) 
+4
source

Source: https://habr.com/ru/post/1266463/


All Articles