2

What is the best way to deal with null values, when doing Collections.sort() on nested objects?

I'd like to sort a couple of objects, basically applying this rule:

@Override
public int compare(final InvoicePos invoicePosOne, final InvoicePos invoicePosTwo) {
   return invoicePosOne.getInvoice().getInvoiceNo().compareTo(invoicePosTwo.getInvoice().getInvoiceNo());
}

However, any of these objects can be null (i.e. invoice position, invoice and invoice number).

public class InvoicePos {
  private Invoice invoice = null;

  // ...
}

public class Invoice {
  private String invoiceNo = "";

  // ...
}

Do I have do do explicit null-checks on all my objects or is there an approach with less writing?


For clarification: I'm aware that my above example may raise NullPointerExceptions. Currently I'm doing the following and basically, I questioned myself, if there is any smarter approach.

     Collections.sort(allInvoicePositions, new Comparator<InvoicePos>() {
        @Override
        public int compare(final InvoicePos invoicePosOne, final InvoicePos invoicePosTwo) {
           if (null == invoicePosOne && null == invoicePosTwo) {
              return 0;
           }

           if (null == invoicePosOne) {
              return -1;
           }

           if (null == invoicePosTwo) {
              return 1;
           }

           if (null == invoicePosOne.getInvoice() && null == invoicePosTwo.getInvoice()) {
              return 0;
           }

           if (null == invoicePosOne.getInvoice()) {
              return -1;
           }

           if (null == invoicePosTwo.getInvoice()) {
              return 1;
           }

           if (null == invoicePosOne.getInvoice().getInvoiceNo() && null == invoicePosTwo.getInvoice().getInvoiceNo()) {
              return 0;
           }

           if (null == invoicePosOne.getInvoice().getInvoiceNo()) {
              return -1;
           }

           if (null == invoicePosTwo.getInvoice().getInvoiceNo()) {
              return 1;
           }

           return invoicePosOne.getInvoice().getInvoiceNo().compareTo(invoicePosTwo.getInvoice().getInvoiceNo());
        }
     });
3
  • Well, don't allow null values to be inserted in your collection. Also, do null check in your comparator if you know that some fields may be null, otherwise make sure you don't have null values at all. Commented Jan 20, 2015 at 14:46
  • Yes, otherwise you will end up with a NPE in invoicePosOne.getInvoice().getInvoiceNo() -->(getInvoice() returns an instance of Invoice right?. So, if it returns null , then you will have an NPE) Commented Jan 20, 2015 at 14:47
  • 1
    The problem you have is that the sort order needs to be consistent. i.e. if you decide that a < b it must also be true that b > a. You have to chose whether null < x or not. Commented Jan 20, 2015 at 14:49

3 Answers 3

1

There is something called as NullComparator in org.apache.commons.collections.jar.

This might help you https://commons.apache.org/proper/commons-collections/javadocs/api-2.1.1/org/apache/commons/collections/comparators/NullComparator.html.

Sign up to request clarification or add additional context in comments.

4 Comments

Though, I'm not using Apache commons, I like the idea of NullComparator. I had a closer look at this article and I think this could come in handy (if I was using Apache commons).
Yes, you don't have to write explicit null checks, as everything is handled already.
However, it won't handle the nested objects automatically. But still handy. And there is no need to include the entire Apache commons lib, its sufficient to implement your own NullComparator and ComparableComparator class. The code of Apache commons is available online.
Downvoter, can you put comments for improving my answer
1

Do I have do do explicit null-checks on all my objects or is there an approach with less writing?

If these values don't represent anything in your collection, then the best thing you can do is avoid them; don't allow inserting them, so you won't have to handle them when comparing items.

If you insist to have them, then you must check if they're null to avoid NullPointerException.

2 Comments

I'm aware of the NPEs, just looking for a smart way to do all those checks.
@user1438038 consider using a map or encapsulate your data structure to have less comparisons.
0

If you have null values then you need to handle them explicitly and in a consistent way so to have a valid ordering relation. That is, something like:

compare (a, b) {
  if (a == null && b == null) return 0;      
  if (a == null) return -1;
  if (b == null) return +1;
  return comp(a,b);
}

Don't be tempted to do something like:

compare (a, b) {
  if (a == null || b == null) return -1;
  return comp(a,b);
}

which would break the ordering relation.

Comments

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.