266

I have a list of objects say car. I want to filter this list based on some parameter using Java 8. But if the parameter is null, it throws NullPointerException. How to filter out null values?

Current code is as follows

requiredCars = cars.stream().filter(c -> c.getName().startsWith("M"));

This throws NullPointerException if getName() returns null.

3
  • Do you wanna “filter values only if not null” or “filter out null values”? That sounds contradicting to me. Commented Oct 1, 2015 at 10:18
  • 3
    Could I suggest that you accept Tunaki's answer as it appears to be the only one which actually answers your question. Commented May 4, 2017 at 10:14
  • What about kotlin? )) requiredCars = cars.filter {c -> c?.name?.startsWith("M"))}; Commented Dec 17, 2021 at 21:31

7 Answers 7

539
+200

In this particular example, I think @Tagir is 100% correct get it into one filter and do the two checks. I wouldn't use Optional.ofNullable the Optional stuff is really for return types not to be doing logic... but really neither here nor there.

I wanted to point out that java.util.Objects has a nice method for this in a broad case, so you can do this:

    cars.stream()
        .filter(Objects::nonNull)

Which will clear out your null objects. For anyone not familiar, that's the short-hand for the following:

    cars.stream()
        .filter(car -> Objects.nonNull(car))

To partially answer the question at hand to return the list of car names that starts with "M":

    cars.stream()
        .filter(car -> Objects.nonNull(car))
        .map(car -> car.getName())
        .filter(carName -> Objects.nonNull(carName))
        .filter(carName -> carName.startsWith("M"))
        .collect(Collectors.toList());

Once you get used to the shorthand lambdas you could also do this:

    cars.stream()
        .filter(Objects::nonNull)
        .map(Car::getName)        // Assume the class name for car is Car
        .filter(Objects::nonNull)
        .filter(carName -> carName.startsWith("M"))
        .collect(Collectors.toList());

Unfortunately once you .map(Car::getName) you'll only be returning the list of names, not the cars. So less beautiful but fully answers the question:

    cars.stream()
        .filter(car -> Objects.nonNull(car))
        .filter(car -> Objects.nonNull(car.getName()))
        .filter(car -> car.getName().startsWith("M"))
        .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

7 Comments

note that the null car isn't the issue. In this case, it's name property causing problems. So Objects::nonNull can't be used here, and in last advice it should be cars.stream() .filter(car -> Objects.nonNull(car.getName())) I believe
BTW, I think cars.stream() .filter(car -> Objects.nonNull(car.getName()) && car.getName().startsWith("M")) would be the summary of your advice in this question context
@kiedysktos That's a good point that calling .startWith could also cause a null pointer. The point I was trying to make is that Java supplies a method specifically for filtering out null objects from your streams.
@Mark Booth yes, obviously Objects.nonNull is equivalent to != null, your option is shorter
Aren't you creating a list of car names (String) instead cars (Car)?
|
94

You just need to filter the cars that have a null name:

requiredCars = cars.stream()
                   .filter(c -> c.getName() != null)
                   .filter(c -> c.getName().startsWith("M"));

4 Comments

It's a real shame that this answer isn't more highly voted as it appears to be the only answer that actually answers the question.
@MarkBooth The question "How to filter out null values?" seems to be answered well by xbakesx.
@MarkBooth Looking at the dates you are correct. My mistake.
Performance wise is it good to filter the stream twice Or better use the predicate for filtering? Just want to know.
69

The proposed answers are great. Just would like to suggest an improvement to handle the case of null list using Optional.ofNullable, new feature in Java 8:

List<String> carsFiltered = Optional.ofNullable(cars)
                    .orElseGet(Collections::emptyList)
                    .stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

So, the full answer will be:

List<String> carsFiltered = Optional.ofNullable(cars)
                    .orElseGet(Collections::emptyList)
                    .stream()
                    .filter(Objects::nonNull) //filtering car object that are null
                    .map(Car::getName) //now it's a stream of Strings
                    .filter(Objects::nonNull) //filtering null in Strings
                    .filter(name -> name.startsWith("M"))
                    .collect(Collectors.toList()); //back to List of Strings

4 Comments

Bad use of Optional. null should never be used as a synonym for an empty Collection in the first place.
@VGR Of course, but that is not what happens in practice. Sometimes (most of the time) you need to work with code that a lot of people worked on. Sometime you receive your data from external interfaces. For all those cases, Optional is a great use.
note that the null car isn't the issue. In this case, it's name property causing problems. So Objects::nonNull doesn't solve the problem since non-null car can have name==null
Of course @kiedysktos, but that's not what I wanted to show in the answer. But, I'm accepting what you saying and editing the answer :)
32

You can do this in single filter step:

requiredCars = cars.stream().filter(c -> c.getName() != null && c.getName().startsWith("M"));

If you don't want to call getName() several times (for example, it's expensive call), you can do this:

requiredCars = cars.stream().filter(c -> {
    String name = c.getName();
    return name != null && name.startsWith("M");
});

Or in more sophisticated way:

requiredCars = cars.stream().filter(c -> 
    Optional.ofNullable(c.getName()).filter(name -> name.startsWith("M")).isPresent());

1 Comment

The inline expansion in the second example was valuable for my use case
4

you can use this

List<Car> requiredCars = cars.stream()
    .filter (t->  t!= null && StringUtils.startsWith(t.getName(),"M"))
    .collect(Collectors.toList());

Comments

4

Leveraging the power of java.util.Optional#map():

List<Car> requiredCars = cars.stream()
  .filter (car -> 
    Optional.ofNullable(car)
      .map(Car::getName)
      .map(name -> name.startsWith("M"))
      .orElse(false) // what to do if either car or getName() yields null? false will filter out the element
    )
  .collect(Collectors.toList())
;

1 Comment

Using the complexity of Optional to replace a simple boolean expression is bad practice imho.
0

You can apply Objects.nonNull or you can put null check on car object inside filter and also apply other condition as well in the same filter method.

List<Car> list = carsList.stream()
         .filter(c-> Objects.nonNull(c) && c.getName().startWith("M"))
         .collect(Collectors.toList());

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.