0

Is there a better way of sorting a collection in Java-8 without checking first if collection is empty or null?

if (institutions != null && !institutions.isEmpty()) {
        Collections.sort(institutions);
    }
quma
  • 5,233
  • 26
  • 80
  • 146
  • 7
    There is no need to check for an empty collection at all. The `null` check is best avoided by never letting the collection be `null` in the first place. – Holger Aug 22 '16 at 13:20

2 Answers2

1

Though the question is old, just adding another way of doing it. First of all, the collection shouldn't be null. If so:

institutions.sort(Comparator.comparing(Institutions::getId));
human
  • 168
  • 1
  • 10
0

I can only think of 3 (4) ways:

  1. Use a SortedSet (e.g. TreeSet) and insert it there. Elements will be sorted right away, however insertion time may be bad. Also, you can not have equal elements in there (e.g. 3x 1), so it might not be the best solution.

Then there is the normal Collections.sort(). You don't have to check that your list is empty, however you do have to make sure it is not null. Frankly though, do you ever have a use case where your list is null and you want to sort it? This sounds like it might be a bit of a design issue.

Finally you can use streams to return sorted streams. I wrote up a little test that measures the time of this:

public static void main(String[] args) {
        List<Integer> t1 = new ArrayList<>();
        List<Integer> t2 = new ArrayList<>();
        List<Integer> t3 = new ArrayList<>();
        for(int i = 0; i< 100_000_00; i++) {
            int tmp = new Random().nextInt();
            t1.add(tmp);
            t2.add(tmp);
            t3.add(tmp);
        }

        long start = System.currentTimeMillis();
        t1.sort(null); // equivalent to Collections.sort() - in place sort
        System.out.println("T1 Took: " + (System.currentTimeMillis() - start));

        start = System.currentTimeMillis();
        List<Integer> sortedT2 = t2.stream().sorted().collect(Collectors.toList());
        System.out.println("T2 Took: " + (System.currentTimeMillis() - start));

        start = System.currentTimeMillis();
        List<Integer> sortedT3 = t3.parallelStream().sorted().collect(Collectors.toList());
        System.out.println("T3 Took: " + (System.currentTimeMillis() - start));
    }

Sorting random integers results in: (on my box obviously)

Collections.sort() -> 4163
stream.sorted() -> 4485
parallelStream().sorted() -> 1620

A few points:

Collections.sort() and List#sort will sort the existing list in place. The streaming API (both parallel and normal) will created new sorted lists.

Again - the stream can be empty, but it can't be null. It appears that parallel streams are the quickest, however you have to keep in mind the pitfalls of parallel streams. Read some info e.g. here: Should I always use a parallel stream when possible?

Finally, if you want to check for null before, you can write your own static helper, for example:

public static <T extends Comparable<? super T>> void saveSort(final List<T> myList) {
        if(myList != null) {
            myList.sort(null);
        }
    }

    public static <T> void saveSort(final List<T> myList, Comparator<T> comparator) {
        if(myList != null) {
            myList.sort(comparator);
        }
    }

I hope that helps!

Edit: Another Java8 advantage for sorting is to supply your comparator as lambda:

List<Integer> test = Arrays.asList(4,2,1,3);
test.sort((i1, i2) -> i1.compareTo(i2));
test.forEach(System.out::println);
Community
  • 1
  • 1
pandaadb
  • 6,306
  • 2
  • 22
  • 41
  • Might be noted that `Collections.sort` and `List.sort` will sort in-place, while the `stream` solutions create a sorted copy (which is thrown away in your code). – tobias_k Aug 22 '16 at 13:08
  • @tobias_k thanks, I adopted my answer to reflect those points – pandaadb Aug 22 '16 at 13:12
  • 2
    It’s hard to find the two sentences which actually answer the question within that long answer talking about things never asked for… – Holger Aug 22 '16 at 13:22