简体   繁体   中英

Dealing with a null attribute using java 8 streams and sorting using lambda expressions

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?

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;

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.

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.

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

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());

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. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM