1

How can i rewrite this:

private Comparator<Domain> byRank;

...

byRank = new Comparator<Domain>() {
  @Override
  public int compare(Domain d1, Domain d2) {
    float tmp1 = d1.getDomainRank() == null ? 0 : d1.getDomainRank();
    float tmp2 = d2.getDomainRank() == null ? 0 : d2.getDomainRank();
    return Float.compare(tmp1, tmp2);
  }
};

into lambda?

According to check null value before sorting using lambda expression, I tried this:

byRank = Comparator.nullsFirst(Comparator.comparing(Domain::getDomainRank));

However, it fails with:

java.lang.NullPointerException: null
    at java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:469)
    at java.util.Comparators$NullComparator.compare(Comparators.java:83)
    at java.util.PriorityQueue.siftUpUsingComparator(PriorityQueue.java:669)
    at java.util.PriorityQueue.siftUp(PriorityQueue.java:645)
    at java.util.PriorityQueue.offer(PriorityQueue.java:344)
    at java.util.PriorityQueue.add(PriorityQueue.java:321)

Edit: the lambda fails even if I check compared objects for null before comparison:

Queue<Domain> topByRank = new PriorityQueue<>(TOP, byRank);

...

for (Domain domain : domains) {
  if (domain == null) { // check here
    continue;
  }
  topByRank.add(domain); // here it fails
}
Community
  • 1
  • 1
Michal
  • 1,955
  • 5
  • 33
  • 56
  • For what I see d1 or d2 should be null – freedev Mar 15 '17 at 10:36
  • @freedev I check for null object (see edit). And the non-lambda version works without failing. Wouldn't it fail on d1.getDomainRank() or d2.getDomainRank() too? – Michal Mar 15 '17 at 10:45
  • Comparator.comparing is throwing the NPE. You have to turn the calls around. See http://stackoverflow.com/a/28500970/982149 – Fildor Mar 15 '17 at 10:46

2 Answers2

5

It should be:

Comparator.comparing(Domain::getDomainRank,
           Comparator.nullsFirst(Comparator.naturalOrder()))

So we sort a list based on domainRank. But what are we going to do with Domain objects whose domainRank value is null? We going to keep them at the head of our collection: Comparator.nullsFirst(Comparator.naturalOrder())

Anton Balaniuc
  • 10,889
  • 1
  • 35
  • 53
2

Your code will put null Domains first. If you want to check for null rank, you need to use this:

Comparator.comparing(Domain::getDomainRank, Comparator.nullsFirst(Comparator.naturalOrder()))

But keep in mind that this is only equivalent to your original comparator if the rank can't be less than 0. Otherwise, you'll have to test a similar expression:

Comparator.comparing(d -> d.getDomainRank() == null ? 0 : d.getDomainRank())

Alternatively, you might have meant to use Float.MIN_VALUE instead of 0 in your original code.

shmosel
  • 49,289
  • 6
  • 73
  • 138