Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Comparator with null fields

I have a list of entities Entity with the fields id and createdDate. I want to sort them as following:

  • higher id first
  • if id null, most recent createdDate first

I've tried the following unsuccessfuly, as it throwns a NullPointerException when id is null

Comparator comp = Comparator
                .nullsFirst(Comparator.comparing(e -> ((Entity) e).getId()))
                .thenComparing(e -> ((Entity e).getCreatedDate())
                .reversed();
entities.stream().sorted(comp).findFirst();

For what I see, Comparator.nullsFirst handles when the entity is null, not when the field to be compared is null. How can I handle this situation?

like image 374
Sergio Lema Avatar asked Jun 14 '19 12:06

Sergio Lema


People also ask

Can we compare NULL values in Java?

We can simply compare the string with Null using == relational operator. Print true if the above condition is true. Else print false.

How do you compare two nulls?

Say you have a table with a NULLable column type, and you want to find rows with a NULL value in that column. Since you can't use a equality operator in the WHERE clause (remember, NULL values can't be equated or compared), the right way to compare NULL values is to use the IS and IS NOT operators.

Can NULL == NULL in Java?

out. println("(Object)string == number: " + ((Object)string == number)); To conclude this post and answer the titular question Does null equal null in Java? the answer is a simple yes.


2 Answers

I think you are looking for comparator like this, using Comparator.nullsLast :

Comparator<MyClass> comparator = Comparator.comparing(MyClass::getId, Comparator.nullsLast(Comparator.reverseOrder()))
                .thenComparing(MyClass::getCreateDate);

The code to test it :

List<MyClass> list = new ArrayList<>();

list.add(new MyClass(null, LocalDate.now()));
list.add(new MyClass(4L, LocalDate.now()));
list.add(new MyClass(2L, LocalDate.now()));
list.add(new MyClass(4L, LocalDate.now().plusDays(1)));
list.add(new MyClass(null, LocalDate.now().plusDays(1)));

Comparator<MyClass> comparator = Comparator.comparing(MyClass::getId, Comparator.nullsLast(Comparator.reverseOrder()))
                .thenComparing(MyClass::getCreateDate);

list.stream().sorted(comparator).forEach(myClass -> System.out.println(myClass.id + " " + myClass.createDate));

The output is :

4 2019-06-14
4 2019-06-15
2 2019-06-14
null 2019-06-14
null 2019-06-15

If you want nulls to be first just change nullsLast to nullsFirst.

like image 68
Michał Krzywański Avatar answered Sep 23 '22 21:09

Michał Krzywański


Extending @Mena's comment:

java.util.Collections.sort(entities, new Comparator<Entity>(){
   @Override
   public int compare(Entity ent1, Entity ent2) {
     Object id1=ent1.getId();
     Object id2 = ent2.getId();
     if (id1!=null && id2!=null)
     {
       return id2.compareTo(id1);
     }
     else
     {
       Date d1 = ent1.getCreatedDate();
       Date d2 = ent2.getCreatedDate();
       return d2.compareTo(d1);
     }
   }
});
like image 39
Oscar Pérez Avatar answered Sep 19 '22 21:09

Oscar Pérez