简体   繁体   中英

Filter values only if not null using lambda in Java8

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 .

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

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

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

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

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

you can use this

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

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