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());
Answer from xbakesx on Stack OverflowIn 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"));
java - Filter Null items in Stream - Stack Overflow
Java stream filter null pointer issue - Stack Overflow
Filter out null values in Java 8 stream filter expression so exception is not thrown - Stack Overflow
ArrayList .addAll, how would I filter out null values?
You can use Objects::nonNull from the Java8 SDK:
.stream()
.<other operations...>
.filter(Objects::nonNull)
.<other operations...>
You can use the Objects::nonNull
Returns true if the provided reference is non-null otherwise returns false.
.stream()
.<other operations...>
.filter(Objects::nonNull)
.<other operations...>
The issue was: I was using .isEmpty() on a null object. I had to use StringUtils.isEmpty() method:
services = services.stream()
.filter(service -> (StringUtils.isEmpty(service.getType()) || service.getType().equals(type)))
.collect(Collectors.toList());
Too late for an answer but still posting this here if anyone comes across this post.
Try to use filter out all the objects which are null or have some property that can be null, before performing any operations on the same.
In this case
list.stream()
//.filter(Objects::nonNull) // use when the whole object can be null
.filter(service->Objects.nonNull(service.getType()))
.filter(service -> (service.getType().isEmpty() || service.getType().equals("Type1")))
.collect(Collectors.toList());
The attributes such as the billingMethod, whenever it is possibly null inside the List, it should still work for comparison to get distinct values.
On the other hand, comparing them with some other String constant can be solved in the manner the user FilipRistic suggested.
But, when it is about objects which could be possibly null and you want to access the inner attributes further down safely, you can make use of Optional and chain the accessors. For a sample amongst those, while you want to access the numberCode of your destination which could possibly be null, you can have an accessor in PurchasedTripSegment class to expose this:
Optional<Integer> getDestinationCode() {
return Optional.ofNullable(this.getDestination()) // empty for 'null'
.map(Node::getNumberCode);
}
With similar changes for other accessors, your overall code would update and change to something like:
filteredList = purchasedTripSegments.stream()
.filter(segment -> PurchasedVendorType.RAIL.equals(segment.getVendorType()))
.filter(distinctByKey(segment -> Arrays.asList(segment.getBillingMethod(),
segment.getOriginCode(), segment.getDestinationCode(),
segment.getStopOffLocationCode())))
.filter(segment -> segment.getBillingMethod().equalsIgnoreCase(BILLING_METHOD_LOCAL) ||
(segment.getBillingMethod().equalsIgnoreCase(BILLING_METHOD_RULE) &&
segment.getDestinationCode().equals(segment.getStopOffLocationCode())))
.collect(Collectors.toList());
No there isn't any way for filter to know that since it doesn't know in which way you will use element inside Predicate, your only solution is to perform the check for null yourself.
Note that you can avoid check in cases where you are comparing to constant that you know isn't null, instead of writing:
segment.getBillingMethod().equalsIgnoreCase(BILLING_METHOD_LOCAL)
You could write it like this:
BILLING_METHOD_LOCAL.equalsIgnoreCase(segment.getBillingMethod())
This will avoid NPE but it only helps you in few cases not all of them, for other cases you will have to perform check or maybe refactor to return type Optional and your condition could look something like this:
segment.getDestination()
.flatMap(d -> segment.getStopOff()
.map(s -> s.getStopOffLocation)
.filter(s -> s.getNumberCode() == d.getNumberCode()) )
.isPresent();