0

I have a list of object, DealPortafoglio. This object has three fields: keySum1, keySum2 and key. I would like to sort the List by keySum1, and if it's null, by keySum2. How can I use the Comparable interface to do that? Thank you in advance

At this moment, the only way I found is to split the list into two lists (one with keySum1 != null and the other with keySum1=null and keySum2 != null) and sort them indipendently.

Raul
  • 115
  • 5
  • 16
  • 1
    How about if the field is null for one object in the list, but not for another object it is being compared with...? – Michael Jul 17 '19 at 10:02
  • 2
    Well, you simply create the correct `Comparator` which uses whatever logic you want when comparing two instances... we cannot really help you implementing it since it's not 100% clear how you want to compare these objects... if you compare an instance where `keySum1` is null with one where it isn't what should happen? Should be simply compare `keySum2` with `keySum1`? Should we compare the two `keysum2`s? Should we always consider the object with `keySum1` as "smaller"? All of these are valid logics that depend on the result you want... – Giacomo Alzetta Jul 17 '19 at 10:03
  • As other said, create a custom comparator and implement your logic. https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html – Fabio Piunti Jul 17 '19 at 10:08

1 Answers1

3

You can combine Comparator.nullsLast() with Comparator.thenComparing().

For example for

@Data
class MyObject {
    private String field1;
    private String field2;
    private String field3;
}

you can create a Comparator like this:

Comparator<MyObject> combined =
    Comparator.comparing(MyObject::getField1, Comparator.nullsLast(Comparator.naturalOrder()))
    .thenComparing(MyObject::getField2, Comparator.nullsLast(Comparator.naturalOrder()))
    .thenComparing(MyObject::getField3, Comparator.nullsLast(Comparator.naturalOrder()));

This will result in a Comparator that first sorts by field1; if it contains null for one of the compared objects contain null, it will be sorted after the other (nullsLast). If the field is null for both objects, the next field will be evaluated (thenComparing()), until field3 is reached.

You can of course create a helper method

private static Comparator<MyObject> compareField(Function<MyObject, String> fieldExtractor) {
    return Comparator.comparing(fieldExtractor, Comparator.nullsLast(Comparator.naturalOrder()));
}

so your combination comparator definition is shorter:

Comparator<MyObject> combined =
    compareField(MyObject::getField1)
        .thenComparing(compareField(MyObject::getField2))
        .thenComparing(compareField(MyObject::getField3));
daniu
  • 14,137
  • 4
  • 32
  • 53