Sorting strings list by descending string length, doesn't change the list

Viewed 151

I want to sort a copy of an immutableList by descending string length. I have to support API below java 8.

I try this basic code, but it's still in reverse order

ImmutableList<String> possibleTexts = ImmutableList.of("aa", "bbbbbb");
final List<String> mutableList = new ArrayList<>(possibleTexts);
Collections.sort(mutableList, (s1, s2) -> Math.abs(s1.length() - s2.length()));

and yet mutableList is "aa", "bbbbbb" instead of "bbbbbb","aa"

4 Answers

Build the Comparator using comparing and select the length as a key and reverse the order

mutableList.sort(Comparator.comparing(String::length).reversed());

Your output is the opposite of what you expect because Math.abs(s1.length() - s2.length()) returns 4 for both |2 - 6| and |6 - 2|.

The documentation of Collections#sort also states the following:

This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.

To fix your issue, you can remove Math#abs and swap your comparison (the length of a String cannot be negative, so no overflow/underflow will occur):

Collections.sort(mutableList, (s1, s2) -> s2.length() - s1.length());

However, I'd recommend using List#sort with Comparator#comparingInt and Comparator#reversed, as it's more readable to me than your current snippet.

 Collections.sort(mutableList,(s1,s2)->Integer.compare(s2.length(),s1.length()));

The sorting itself has already been answered, but you can use a stream rather than create an explicit copy of the list.

List<String> sorted = possibleTexts.stream()
                          .sorted(Comparator.comparing(String::length).reversed())
                          .collect(Collectors.toList());
Related