-1

Short Version

Conceptually something like:

list.sort( StringUtils.compareIgnoreCase(o1.getID(), o2.getID() ));

Long Version

I'm trying to sort a list of thingies:

List<Thingy> list = getListOfThingies();

and thingy has a String member that i want to sort case-insensitively on:

class Thingy {
   private String id;
   public getId() { return id; }
}

I know list has a .sort method:

default void sort(Comparator<? super E> c)

It was enough of a challenge to decipher that syntax, that i managed to cobble together a Comparator<Thingy> class:

    class MyThingySortCompator implements Comparator<Thingy> {

        @Override
        public int compare(Thingy o1, Thingy o2) {
            String s1;
            String s2;
            if (o1 != null) s1 = o1.getId(); // thingy1 could be null - who knows
            if (o2 != null) s2 = o2.getId(); // thingy2 could be null - who knows

            //StringUtils handles if a string is null
            int compareResult = StringUtils.compareIgnoreCase(s1, s2);

            return compareResult;
        }
    }

and then i can sort my list:

List<Thingy> list = getListOfThingies();
Comparator<Thingy> myThingySortComparator = new MyThingySortCompator();
list.sort(myThingySortComparator);

And that works, but that's quite verbose.

I've heard tell that a lambda syntax can do the same thing, in one line (although be quite unreadable). What would be the equivalent lambda syntax?

Research Effort

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • It does kind of look like https://stackoverflow.com/q/37649290/869736, which you already cited, answered this question as well as anything could... – Louis Wasserman Jul 26 '22 at 23:18

1 Answers1

2
import java.util.Comparator;

list.sort(Comparator.comparing(Thingy::getId, String.CASE_INSENSITIVE_ORDER));

or, with the more usual static import,

list.sort(comparing(Thingy::getId, CASE_INSENSITIVE_ORDER));

I don't believe this has any problems with readability.

This does not handle nulls -- and in my opinion, you shouldn't -- but if you wanted to, you would do another static import from Comparator so you could write

list.sort(nullsFirst(comparing(Thingy::getId, CASE_INSENSITIVE_ORDER))); 

or if Thingy.getId() could also be null (why are you letting nulls in your program, again? they almost universally indicate bugs)

list.sort(nullsFirst(comparing(Thingy::getId, nullsFirst(CASE_INSENSITIVE_ORDER))));

or if using non static imports:

using java.util.Comparator;

//Sort list, case insensitively, without crashing if a null is accidentally present.
list.sort(Comparator.nullsFirst(Comparator.comparing(Thingy::getId, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER))));
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • What's the syntax for the 2nd example with the *static* import? I tried `import static java.util.Comparator.comparing;` but that doesn't compile. – Ian Boyd Jul 27 '22 at 12:47
  • The only issue with readability is `::` and the lack of braces on a method call. But it is better than i was expecting, which was something like `(x,y) --> StringUtil.sort(x.getID(), y.getID())` – Ian Boyd Jul 27 '22 at 12:49
  • *"why are you letting nulls in your program, again?"* It isn't my choice. Java continues to allow reference types to be null. C# fixed it so that reference types (e.g. `Object`, `String`, `List` can never be null). But this isn't C#, so we have to deal with them. – Ian Boyd Jul 27 '22 at 13:16
  • @IanBoyd: You can choose several ways to deal with nulls in Java, including to [crash when you receive them](https://en.wikipedia.org/wiki/Fail-fast) so your tests will fail when nulls sneak into your program. – Louis Wasserman Jul 27 '22 at 16:46
  • In this case nulls should not exist (i.e. reference types should not be allowed to ever be null). Which means that if a `null` ever did show up - it should have been `""`. (think Python's `None`: which acts like an empty string when asked). – Ian Boyd Jul 27 '22 at 18:43
  • What a language makes possible and what practices you choose to follow in your project are not necessarily tied to each other. You can disagree with Java's choices for perfectly valid reasons. All I'm saying is that it's quite possible to adopt Java design practices that mean you don't have to worry about these issues, that the language doesn't _force_ you to add null checks everywhere. – Louis Wasserman Jul 27 '22 at 19:25
  • Well, you have to ask yourself, *"What if the value were null? What is the way to recover from this `NullReferenceException`?"* Java is very big on declaring all possible exceptions, either handling them, or letting them go up the call chain. If i were to encounter a `null` reference while sorting a list of items: is it a fatal unrecoverable condition? Absolutely not. I absolutely can recover from it, and handle it exactly how i would expect it to be handled: sort them. The guy who invented `null` calls them *the billion dollar mistake* for a good reason. – Ian Boyd Jul 27 '22 at 19:28
  • To the contrary: if the value were `null`, then that probably indicates a bug in the code that passed in `null`. I should throw an unhandled exception immediately, so my tests will fail, so I catch the issue and can debug it before pushing to production. If I just sort the nulls, it covers up the issue and makes it harder to detect; I don't get any sort of alert that something is wrong. – Louis Wasserman Jul 27 '22 at 20:37
  • Hence why nulls continue to be the billion dollar mistake. Developers let them fly and they leak into production (even with all the testing in the world). – Ian Boyd Jul 27 '22 at 20:46