Filter values only if not null using lambda in Java8
Solution 1
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());
Solution 2
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"));
Solution 3
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
Solution 4
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());
Solution 5
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())
;
Related videos on Youtube
vaibhavvc1092
Updated on December 15, 2021Comments
-
vaibhavvc1092 over 2 years
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 isnull
, it throwsNullPointerException
. How to filter out null values?Current code is as follows
requiredCars = cars.stream().filter(c -> c.getName().startsWith("M"));
This throws
NullPointerException
ifgetName()
returnsnull
.-
Holger over 8 yearsDo you wanna “filter values only if not null” or “filter out null values”? That sounds contradicting to me.
-
MarkSwears almost 7 yearsCould I suggest that you accept Tunaki's answer as it appears to be the only one which actually answers your question.
-
JustAnotherCoder over 2 yearsWhat about kotlin? )) requiredCars = cars.filter {c -> c?.name?.startsWith("M"))};
-
-
VGR over 7 yearsBad use of Optional. null should never be used as a synonym for an empty Collection in the first place.
-
Johnny over 7 years@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.
-
kiedysktos over 7 yearsnote 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 becars.stream() .filter(car -> Objects.nonNull(car.getName()))
I believe -
kiedysktos over 7 yearsBTW, 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 over 7 yearsnote 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 -
xbakesx over 7 years@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. -
MarkSwears almost 7 yearsIt'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.
-
kiedysktos almost 7 years@Mark Booth yes, obviously
Objects.nonNull
is equivalent to!= null
, your option is shorter -
vegemite4me almost 7 years@MarkBooth The question "How to filter out null values?" seems to be answered well by xbakesx.
-
vegemite4me almost 7 years@MarkBooth Looking at the dates you are correct. My mistake.
-
Johnny over 6 yearsOf 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 :)
-
user1803551 over 5 yearsAren't you creating a list of car names (
String
) instead cars (Car
)? -
xbakesx over 5 yearsDefinitely right, once you map to
getName
it's just a list of Strings. I'll update the answer. Thank you! -
Vaibhav_Sharma about 5 yearsPerformance wise is it good to filter the stream twice Or better use the predicate for filtering? Just want to know.
-
Aníbal about 5 yearsIt's more efficient to use the method reference Objects:nonNull (first option) than using the arrow operator that instance an object.
-
Paul about 4 yearsThe inline expansion in the second example was valuable for my use case