34

I want to sort String elements in the array months by length using Arrays.sort method. I was told here, that it's possible to use lambda expressions instead of creating new class implementing Comparator. Did it exactly the same way, yet it doesn't work.

import java.util.Arrays;
import java.util.Comparator;

public class MainClass {
public static void main(String[] args)
{

    String[] months = {"January","February","March","April","May","June","July","August","September","October","December"};

    System.out.println(Arrays.toString(months)); //printing before


    //neither this works:
    Arrays.sort(months, 
            (a, b) -> Integer.signum(a.length() - b.length())   
    );

    //nor this:
    Arrays.sort(months, 
            (String a, String b) -> { return Integer.signum(a.length() - b.length()) }; 
    );


    System.out.println(Arrays.toString(months)); //printing after
}
}
matt-pielat
  • 1,659
  • 3
  • 20
  • 33

4 Answers4

86

The cleanest way would be:

Arrays.sort(months, Comparator.comparingInt(String::length));

or, with a static import:

Arrays.sort(months, comparingInt(String::length));

However, this would work too but is more verbose:

Arrays.sort(months,
            (String a, String b) -> a.length() - b.length());

Or shorter:

Arrays.sort(months, (a, b) -> a.length() - b.length());

Finally your last one:

Arrays.sort(months, 
    (String a, String b) -> { return Integer.signum(a.length() - b.length()) }; 
);

has the ; misplaced - it should be:

Arrays.sort(months, 
    (String a, String b) -> { return Integer.signum(a.length() - b.length()); }
);
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 2
    +1 for showing `Comparator.comparing`, it is so much easier to grasp than writing a custom lambda or `Comparator`. – skiwi Feb 23 '14 at 16:17
  • Well, that's helpful, but I'd like to know what's wrong with my solution. – matt-pielat Feb 23 '14 at 16:18
  • @lavsprat I have added something showing your syntax error. – assylias Feb 23 '14 at 16:19
  • 1
    I suggest using `Integer.compare` instead of signum of `-`. – Peter Lawrey Feb 23 '14 at 16:22
  • 1
    @PeterLawrey Indeed - `signum(a-b)` has the risk of overflowing (even if it's unlikely for strings). – assylias Feb 23 '14 at 16:23
  • @lavsprat Then you don't have java 8 installed or you are not compiling with the right JDK or your IDE does not support it or you have a very old version or... – assylias Feb 23 '14 at 16:25
  • Oracle site says "You have the recommended Java installed (Version 7 Update 51).". – matt-pielat Feb 23 '14 at 16:27
  • 1
    @lavsprat huh.... Version 7 != Version 8... Java 8 is here: https://jdk8.java.net/download.html – assylias Feb 23 '14 at 16:28
  • 1
    I don't think `-` can overflow in this case, as both values are non-negative. – Stuart Marks Feb 23 '14 at 17:03
  • `Integer.signum` is obsolete. Just returning `a-b` (for these special `a` and `b` where `a-b` cannot overflow, of course) is enough. There is no need to set the absolute value to `1`. So wrapping a value which has the right sign already with an `Integer.signum(…)` call makes no sense for a `Comparator`. – Holger Feb 24 '14 at 11:38
  • I certainly prefer `Comparator.comparingInt()` over `comparing()` when what you are comparing are indeed `int`s. It’s clearer (and also avoids unnecessary boxing). – Ole V.V. Oct 28 '16 at 12:04
3

You're looking for this:

Arrays.sort(months, (a, b) -> Integer.signum(a.length() - b.length()));
Josh M
  • 11,611
  • 7
  • 39
  • 49
  • Works for me... Are you sure you're using Java 8? Which IDE are you using? – Josh M Feb 23 '14 at 16:18
  • 1
    @lavsprat It also works for me, it prints `[May, June, July, March, April, August, January, October, February, December, September]`... What Java 8 version are you using? – skiwi Feb 23 '14 at 16:20
  • I'm using Eclipse. [This](http://www.java.com/en/download/installed.jsp?detect=jre) site says I have Version 7 Update 51. – matt-pielat Feb 23 '14 at 16:26
  • 2
    Well of course you can't use lambdas then, as they are only available in Java 8. – Josh M Feb 23 '14 at 16:29
2

The functionality you are looking for is in Java 8, which has not yet been released. It is scheduled for release in a few months if you want to wait, or if not beta downloads are available.

Tim B
  • 40,716
  • 16
  • 83
  • 128
0

You can try this:

Arrays.sort(months, (a,b) -> Integer.compare(a.length(), b.length()));
  • 1
    Note that `Integer#compare` doesn't state it, but the return value is always `-1`, `0`, or `1` (whereas the javadoc implies it's merely `<0` or `>0`, so it is subject to change). `#signum` explicitly states this relationship. Either way, for `Arrays#sort`, I don't see what this answer contributes that the others didn't already cover 9 years ago. – Rogue Aug 09 '23 at 15:11