Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Comparator.comparing doesn't work with String::toLowerCase method reference?

I am trying to sort an array of Strings by reverse order (ignoring case), without modifying it, and just printing it. So I am using Java8 stream. But I can't manage to do it.

Here is my attempt :

package experimentations.chapter02;

import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.Collectors;

public class StringStream {

    public static void main(String[] args) {
        sortStrings();
    }

    public static void sortStrings(){
        String[] stringsArray = "The quick brown fox has a dirty ladder".split("\\s+");
        System.out.println(
                Arrays.stream(stringsArray)
                .sorted(Comparator.comparing(String::toLowerCase).reversed())
                .collect(Collectors.toList())
        );
    }

}

The problem here is that String::toLowerCase is not accepted in the static method Comparator.comparing.

Meanwhile, I managed to sort the array, but modifying it:

public static void sortStrings(){
        String[] stringsArray = "The quick brown fox has a dirty ladder".split("\\s+");
        System.out.println(
                Arrays.stream(stringsArray)
                .map(String::toLowerCase)
                .sorted(Comparator.reverseOrder())
                .collect(Collectors.toList())
        );
}

So, what is the simpliest workaround?

like image 820
loloof64 Avatar asked Apr 08 '14 12:04

loloof64


2 Answers

I found the solution :

 .sorted((String e) -> e.toLowerCase) 

I think the problem with the syntax

 .sorted(String::toLowerCase)

is that the compiler then expects to pass an Object to the instance method toLowerCase of String. So I need to make my own lambda method, without ignoring the type of the lambda parameter (String), otherwise the compiler still can't resolve it.

like image 79
loloof64 Avatar answered Oct 20 '22 16:10

loloof64


The problem is, that Java can not deduce the generic types for some complex expressions. The first statement works, whereas the second statement leads to a compile-time error:

Comparator<String> comparator = Comparator.comparing(String::toLowerCase);
Comparator<String> comparator = Comparator.comparing(String::toLowerCase).reversed();

There are several ways to solve the problem. Here are three of them:

Store the intermediate Comparator in a variable:

Comparator<String> comparator = Comparator.comparing(String::toLowerCase);
System.out.println(
            Arrays.stream(stringsArray)
            .sorted(comparator.reversed())
            .collect(Collectors.toList()));

Use String.CASE_INSENSITIVE_ORDER:

System.out.println(
            Arrays.stream(stringsArray)
            .sorted(String.CASE_INSENSITIVE_ORDER.reversed())
            .collect(Collectors.toList()));

Add explicit type parameters:

System.out.println(
            Arrays.stream(stringsArray)
            .sorted(Comparator.<String,String>comparing(String::toLowerCase).reversed())
            .collect(Collectors.toList()));
like image 23
nosid Avatar answered Oct 20 '22 17:10

nosid