I have a Java 8 stream expression that has 3 filters and works fine. I want to guard against null pointer exceptions within the filters for most of the values. This is the expression:
if(!purchasedTripSegments.isEmpty()) {
filteredList = purchasedTripSegments.stream()
.filter(segment -> PurchasedVendorType.RAIL.equals(segment.getVendorType()))
.filter(distinctByKeys(segment -> Arrays.asList(segment.getBillingMethod(),
segment.getOrigin().getNumberCode(), segment.getDestination().getNumberCode(),
segment.getStopOff().getStopOffLocation().getNumberCode())))
.filter(segment -> segment.getBillingMethod().equalsIgnoreCase(BILLING_METHOD_LOCAL) ||
(segment.getBillingMethod().equalsIgnoreCase(BILLING_METHOD_RULE) &&
segment.getDestination().getNumberCode() !=
segment.getStopOff().getStopOffLocation().getNumberCode()))
.collect(Collectors.toList());
}
So the VendorType cannot be null. So the first filter will be fine. The 2nd and 3rd filters can have nulls. The objects (Origin, Destination, StopOff, StopOffLocation) can be null. And the values (BillingMethod, NumberCode) can be null.
Is there a way to ignore the filter if any of the values in the filter are nulls?
I tried adding .filter(Objects::nonNull)
I have a test case that has a null destination object and the NullPointerException is thrown.
UPDATE I updated the billingMethod. But I am not clear on how to use Optional to avoid the null checks.
Optional<List<PurchasedTripSegment>> filteredList = Optional.ofNullable(new ArrayList<>());
if(!purchasedTripSegments.isEmpty()) {
filteredList = purchasedTripSegments.stream()
.filter(segment -> PurchasedVendorType.RAIL.equals(segment.getVendorType()))
.filter(distinctByKeys(segment -> Arrays.asList(segment.getBillingMethod(),
segment.getOrigin().getNumberCode(),
segment.getDestination().getNumberCode(),
segment.getStopOff().getStopOffLocation().getNumberCode())))
.filter(segment -> BILLING_METHOD_LOCAL.equals(segment.getBillingMethod())
|| (BILLING_METHOD_RULE.equals(segment.getBillingMethod()) &&
segment.getDestination().getNumberCode() !=
segment.getStopOff().getStopOffLocation().getNumberCode()))
.collect(Collectors.toList());
}
I'm not sure how to apply the changes you suggested to my filter. I tried adding as written but the map() was not recognized. The middle filter would be the most difficult. How to check the objects and values for each segment?
UPDATE As per the comment below implementing a Utility method using Optional.
private Optional<Integer> getDestinationCode(PurchasedCostTripSegment purchasedCostTripSegment) {
return Optional.ofNullable(purchasedCostTripSegment.getDestination()) // empty for 'null'
.map(Destination::getNumberCode);
}
I do a null check for the incoming parameter.
I get an error that the method getNumberCode is not recognized.