15

Let's consider a Parent class which contains only one Integer attribute. I created 6 objects of parent class and values of attribute are 100, 20, 300, 400, 500, null.

Now I added all the objects to a list(Name of list is list). Then I want to get the objects whose attribute value is greater than 100. I used Java 8 streams for this purpose.

Predicate<Entity> predicate = e -> e.getParentId() < 100;
result = list.stream().filter(predicate).collect(Collectors.toList());

I also want to sort the list in descending order. I used the following code for this purpose.

Comparator<Entity> comp = (d1,d2) -> d2.getId().compareTo(d1.getId());
list.sort(comp);

In both cases I get a NullPointerException.

How to handle this?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Manu Joy
  • 1,739
  • 6
  • 18
  • 30
  • 1
    possible duplicate of [How should we manage jdk8 stream for null values](http://stackoverflow.com/questions/17081063/how-should-we-manage-jdk8-stream-for-null-values) – Nir Alfasi Jul 08 '15 at 05:39
  • 2
    I'm unclear... is it `e` that is `null`, or `e.getParentId()`? If `e.getParentId()` is declared as an `Integer` (the boxed type), it may be null. But then when it's converted to an `int` to compare it to 100, the result will be a `NullPointerException` if it's `null`. – ajb Jul 08 '15 at 05:44

6 Answers6

18

All of the answers here revolve around "throw out the bad elements, those that have a null getParentId()." That may be the answer, if they are indeed bad. But there's another alternative: Comparators.nullsFirst (or last.) This allows you to compare things treating a null value as being less than (or greater than) all non-null values, so you don't have to throw the elements with a null parentId away.

Comparator<Entity> cmp = nullsLast(comparing(Entity::getParentId));
List<Entity> list = list.stream().sorted(cmp).collect(toList());

You can do a similar thing for filtering; define your predicate as:

Predicate<Entity> predicate = e -> e.getParentId() != null 
                                       && e.getParentId() < 100;
Brian Goetz
  • 90,105
  • 23
  • 150
  • 161
18

Looks like you are looking for something like:

list.sort(Comparator.comparing(Entity::getParent, 
                               Comparator.nullsLast(Integer::compareTo)));

All the elements with parent null will be put at the end and the rest will be sorted by their parent.

joetde
  • 1,556
  • 1
  • 16
  • 26
7

Try pre-filtering for non-null parentId values only:

result = list.stream().filter(e -> e.getParentId() != null).filter(predicate).collect(Collectors.toList());

[edit] Just saw, that the attribute (e.parentId) seems the one being null. In that case, the second thing, the sorting, breaks. You are sorting the original list, not the filtered one. Try result.sort(comp), then you should avoid the NPE.

Dominik Sandjaja
  • 6,326
  • 6
  • 52
  • 77
  • 6
    This should work. You can also do `.filter(Objects::nonNull)` – Nir Alfasi Jul 08 '15 at 05:38
  • The problem is object is not null, but the attribute is null,if my contains 100 attributes, and I created a list of that objects , in which many attribute may have null value in some of the objects in the list, how should i handle this. – Manu Joy Jul 08 '15 at 06:48
4

You can do it all in one Stream pipeline :

List<Entity> result =  
    list.stream()
        .filter(e -> e.getParentId()!=null) // it's not clear if the null
                                            // is the Entity object itself
                                            // (in which case it should be e!=null)
                                            // or just the ParentId member
        .filter(predicate)
        .sorted(comp)
        .collect(Collectors.toList());

BTW, according to the text of your question, the original predicate should be :

Predicate<Entity> predicate = e -> e.getParentId() > 100; // not < 100
Eran
  • 387,369
  • 54
  • 702
  • 768
  • 2
    Won't this filter `e.getParentId() == null` elements? He is talking about `e` being null. – Codebender Jul 08 '15 at 05:41
  • 2
    @Codebender I may be misreading the question, but it seemed that OP created objects with parent IDs of `100,20,300,400,500,null`, so I assumed the null referred to ParentId. I might be wrong. – Eran Jul 08 '15 at 05:44
  • @Codebender that's not clear. I think he's talking about the parentId being null, which is possible if it's an `Integer`. – ajb Jul 08 '15 at 05:46
2

Harness the power of a method reference to make the code even more compact:

   List<Entity> result =
            list.stream()
                    .filter(Objects::nonNull) 
                    .filter(predicate)
                    .sorted(comp)
                    .collect(Collectors.toList());
Fritz Duchardt
  • 11,026
  • 4
  • 41
  • 60
1

You can do:

Predicate<Entity> predicate = e -> e.getParentId() < 100;
Predicate<Entity> nonNull = e -> e != null;
result = list.stream().filter(nonNull)
                      .filter(predicate)
                      .collect(Collectors.toList());

Of course, you could combine the predicates into one, but I introduced a second one for better readability. Also, you're free to change the nonNull predicate to check either the whole entity, or just the id attribute (or even both). Just play a bit with it. :)

Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147