47

When using Collection.sort in Java what should I return when one of the inner objects is null

Example:

Collections.sort(list, new Comparator<MyBean>() {
    public int compare(MyBean o1, MyBean o2) {
      return o2.getDate().compareTo(o1.getDate());
     } 

});

Lets say o2 is not null but o2.getDate() it is, so should I return 1 or -1 or 0 when adding a null validation?

6 Answers 6

62

Naturally, it's your choice. Whatever logic you write, it will define sorting rules. So 'should' isn't really the right word here.

If you want null to appear before any other element, something like this could do

public int compare(MyBean o1, MyBean o2) {
    if (o1.getDate() == null) {
        return (o2.getDate() == null) ? 0 : -1;
    }
    if (o2.getDate() == null) {
        return 1;
    }
    return o2.getDate().compareTo(o1.getDate());
} 
Sign up to request clarification or add additional context in comments.

4 Comments

What if you want to sort so in ascending its nulls in front but descending they are at the end. In essence completely flip the list?
I used this code and tried Collections.reverseOrder() and that didnt work same with Collections.reverse(List);
@Jeremy yes u are right i face the same issue all null value data come first and valued data come at end.
@Jeremy I got the solution just interchange the value of -1 and 1. It works fine and null value data will come at the bottom.
54

In Java 8 you can also use nullsFirst():

Comparator.nullsFirst(Date::compareTo).compare(dateOne, dateTwo);

Or nullsLast():

Comparator.nullsLast(Date::compareTo).compare(dateOne, dateTwo);

These methods will either sort null to the beginning or to the end. There is no wrong or right whether you consider null bigger or smaller than another objects. This is totally up to you, as others stated already.

1 Comment

It should be the accepted answer, it's concise, it puts the right responsibility at the right place, i.e Comparable.compareTo() should throw a NullPointerException on nulls whereas a Comparator can optionally handle nulls.
11

Depending on whether the object is null, or the content of the object is null.

The object is null:

    import static java.util.Comparator.*;

    List<Data> listOfData = Arrays.asList(
           new Data("foo"),
           null,
           new Data("bar"),
           new Data("nyu"));

    listOfData.sort(nullsFirst(comparing(Data::getValue)));
    listOfData.forEach(System.out::println);
    //OUTPUT:
    // null
    // Data(bar)
    // Data(foo)
    // Data(nyu)

The content of the object is null:

    List<Data> listOfData = Arrays.asList(
           new Data("foo"),
           new Data(null),
           new Data("bar"),
           new Data("nyu"));


    listOfData.sort(nullsFirst(
         comparing(Data::getValue, nullsFirst(naturalOrder()))));

    listOfData.forEach(System.out::println);
    //OUTPUT:
    // Data(null)
    // Data(bar)
    // Data(foo)
    // Data(nyu)

1 Comment

I have question. what is this called Data::getValue and also if I have another object inside getValue say getRealValue so how will I write it? Data::getValue::getRealValue??
3

It depends, do you consider null as a big value or a low value.

You can consider most of the time that null < everything else, but it depends on the context.

And 0 would be a terrible return value here.

Comments

1

Following the answer from Nikita Rybak, i'm already have a enum comparator, and only add the null logic from here.

public enum Orden implements Comparator<CmunParametrosDTO> {
        ByStrDescripcion {
            public int compare(CmunParametrosDTO item1, CmunParametrosDTO item2) {
                if (item1.getStrDescripcion() == null && item2.getStrDescripcion() == null)
                    return 0;
                if (item1.getStrDescripcion() == null)
                    return 1;
                else if (item2.getStrDescripcion() == null)
                    return -1;
                return item1.getStrDescripcion().compareTo(item2.getStrDescripcion());
            }
        }
        public abstract int compare(CmunParametrosDTO item1, CmunParametrosDTO item2);

        public Comparator<CmunParametrosDTO> ascending() {
            return this;
        }

        public Comparator<CmunParametrosDTO> descending() {
            return Collections.reverseOrder(this);
        }
}

In this form i can call the sort method on my list.

    if(isBolOrdAscendente()) Collections.sort(listado, CmunParametrosDTO.Orden.ByStrDescripcion .ascending());
    else Collections.sort(listado, CmunParametrosDTO.Orden.ByStrDescripcion .descending());

Comments

-1

if comparing two property, attr1 natural order, attr2 reverse order, and attr2 can be null:

datas.sort(comparing(Data::getAttr1, naturalOrder()).
        thenComparing(Data::getAttr2, nullsLast(reverseOrder())));

1 Comment

I have question. what is this called Data::getAttr1. and also if I have another object inside getAttr1 say getAttr2 so how will I write it? Data::getAttr1::getAttr2??

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.