7

Java 8 introduces a new default method on the List interface to sort it. It's signature is :

void sort(Comparator<? super E> c)

The documentation says:

If the specified comparator is null then all elements in this list must implement the Comparable interface and the elements' natural ordering should be used.

So if you want to sort the list by it's natural order (and that your elements are comparable) you have to do list.sort(null); which is kind of weird of my opinion.

If they used an Optional the doc would stated that you can optionally provide a comparator, and that if it's not provided it will assume the elements are already comparable.

A list.sort(null); call would be transformed into list.sort(Optional.empty());.

As it's a method that it exposed to the outside world, I would find it more accurate.

Why didn't they used the new Optional API instead?

user2336315
  • 15,697
  • 10
  • 46
  • 64
  • ...or just force you to pass in a non-null comparator. I'd think that would be much easier all round. – Andy Turner Nov 02 '15 at 21:53
  • 4
    ... or match `Collections`, which provides an overload `sort()` that doesn't take any `Comparator` arguments to sort by the natural order? – rgettman Nov 02 '15 at 21:53
  • 3
    Or just pass `Comparator.naturalOrder()`, it's not that hard, and also much clearer than `null`. – Brian Goetz Nov 02 '15 at 22:24

2 Answers2

13

Optional is intended to be used as a return type. That has always been the mantra of the JDK-8 developers. So they won't break their own rule by using it as an argument.

That said, I would have made the argument mandatory, and thus force the developer to use

list.sort(Comparator.<Foo>naturalOrder());

Even if I can pass null, I find the above more readable, and not much more verbose. So that's what I use in my code.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I didn't know about the first paragraph, and I agree with your last point. Thanks :) – user2336315 Nov 02 '15 at 22:02
  • 1
    See http://stackoverflow.com/questions/26327957/should-java-8-getters-return-optional-type for a longer explanation on the intention, from Brian Goetz himself (the lead JDK8 developer - or whatever his actual title is) – JB Nizet Nov 02 '15 at 22:03
  • Thanks. They could have provided also a default method with no arguments however. – user2336315 Nov 02 '15 at 22:05
  • 1
    @user2336315 I don't think it would have been a good idea. This would have led developers (especially newbies) to think that any list can be sorted, without needing to provide a comparator, whatever the list contains. And this is not the case: only lists of Comparable objects can be sorted. Collections.sort() doesn't have this problem, because it's only callable with a list of Comparables as arguments. – JB Nizet Nov 02 '15 at 22:08
  • I don't like passing `null` either but, `null` is used in many places to mean the natural ordering (e.g. `SortedSet.comparator`. – Paul Boddington Nov 02 '15 at 22:10
  • 2
    I guess it was a dilemma between coherence and cleanliness. One other thing I don't like with "null means natural ordering" is that if your intention is to pass a comparator, and if the code happens to have a bug and you inadvertently pass a null reference, the list is sorted with its natural order rather than failing with a clear exception. It's probably not a common mistake, but still... – JB Nizet Nov 02 '15 at 22:13
  • @JBNizet There's already `Arrays.sort(Object[] a)` (I guess it was introduced before generics but still it's in the API) so I don't find your argument very convincing. Also people should read the doc before blindly run their program IMO. – user2336315 Nov 02 '15 at 22:13
  • 1
    @user2336315 yes, but 1. Arrays.sort() is lower level (just because arrays are lower-level: regular code shouldn't use arrays much. collections should be preferred), 2. This methods dates back to Java 1.2, when generics didn't exist yet. They could have taken a Comparable[] as argument, but this wouldn't have guaranteed that the elements were mutually comparable anyway. The more recent, generic equivalent, is Arrays.sort(T, Comparator). The old one, IMO, is there mainly for backward-compatibility reasons. – JB Nizet Nov 02 '15 at 22:21
  • 1
    @JB Nizet: `Arrays.sort(T[],Comparator super T>)` has the property (just like its `Collections.sort` counterpart) of accepting a `null` comparator and treating it as *natural order*. So `List.sort` follows this pattern, but I agree with you that a mandatory argument was the better choice, because now the *implementor* of `List.sort` is forced to perform unchecked operations to fulfill the contract. Further, this pattern encouraged the `Stream` implementors to optimize for the `null` comparator case and treating `Comparator.naturalOrder()` as second class comparator… – Holger Nov 03 '15 at 10:00
  • For natural order I use good old `Collections.sort(list)` which is type safe and shorter. – Tagir Valeev Nov 03 '15 at 11:41
1

The default method is delegating to Arrays#sort, which has existed since at least Java 1.7.

Here's the relevant snippet for the default method:

@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

Observe that it's converting the list into an array and letting Arrays#sort handle it from there. The default behavior for this then would fall back to what is supported for that method.

There are two reasons why I see this being preferable to adding an Optional:

  • If you don't have a Comparator to use, or just want the "default" behavior, you can provide a null to it. In this context, null and Optional.isPresent() serve the same purpose and would not earn any usability points.

    It is an annoyance to have to provide null to a function for its default behavior; better design might have been to either overload the method or allow a default naturalOrder instance to be passed in instead.

  • The Optional pattern is more meant to guard against inadvertently handling a null reference, as opposed to being used for a null check. The overhead in adding Optional where a simple null check would suffice would far outweigh its benefits, especially considering that there is no semantic difference.

Community
  • 1
  • 1
Makoto
  • 104,088
  • 27
  • 192
  • 230
  • There's also `Arrays.sort(Object[] o)` so they could take it from there to depending if the value is present or not. You convinced me on your last point though, so +1. – user2336315 Nov 02 '15 at 22:00
  • If they did that, they'd be ignoring the parameter passed which is *terrible* design. At the bare minimum, the user as the *chance* to provide their own `Comparator`, but if they elect to pass `null`, then the natural order wins. – Makoto Nov 02 '15 at 22:01
  • That’s not convincing. If the parameter was `Optional`, delegating to `Arrays.sort` just required a simple call to `orElse(null)` to convert an `Optional` to a nullable `Comparator`. But a single particular implementation shouldn’t be the driving force behind an API design anyway (and it isn’t). By the way, if a method has no “Since” marker, it’s usually as old as the class itself, which is in the case of `java.util.Arrays` “*Since: 1.2*” – Holger Nov 03 '15 at 10:06