Following code was an existing code in my project, using the same concept, I am updating the project,
public static List<Option> filterNetworkSettingsOptionBySetting(NetworkSettingsGroup group,
String settingName) {
LOGGER.info("************ Filtering Option based on SettingName ************");
LOGGER.info("***** Setting Name "+settingName);
List<Option> newOptions = new ArrayList<Option>();
if (group == null || group.getOptions() == null || group.getOptions().isEmpty()
|| StringUtils.isBlank(settingName))
return newOptions;
List<Option> oldOptions = group.getOptions();
LOGGER.info("Before Filtering Options "+oldOptions);
Stream<Option> stream = oldOptions.stream();
LOGGER.info("Before Filtering Stream "+stream);
newOptions.addAll(group.getOptions().stream()
.filter(option -> option.getName().equalsIgnoreCase(settingName)).collect(Collectors.toList()));
return newOptions;
}
I am getting NullPointerException at
newOptions.addAll(group.getOptions().stream()
.filter(option -> option.getName().equalsIgnoreCase(settingName)).collect(Collectors.toList()));
this step..
I am not able to understanding that step, can anyone explain me the step clearly... what is happening in that step and how can I divide that step into multiple steps(because I want to check in method call null is coming).
The statement you have asked to be explained is:
newOptions.addAll(group.getOptions().stream()
.filter(option -> option.getName()
.equalsIgnoreCase(settingName))
.collect(Collectors.toList()));
addAll takes a collection so the statement inside returns a collection (a list, in fact).
group.getOptions() must be returning a collection. This should not be null.
.stream() turns the collection into a stream of items
.filter(option -> option.getName().equalsIgnoreCase(settingName)) filters the stream of options to only have options whose name equals settingName (ignoring case).
.collect(Collectors.toList()) turns the stream into a list to be added to newOptions.
In terms of checking for nulls, all the methods mentioned above are not able to return a null: they all return either a Stream or a List. However the getName method of options could be. So, realistically, it is either getOptions or getName that is returning a null value.
I would suggest changing to the following:
Collection<Option> options = group.getOptions();
assert(options != null);
assert(settingName != null);
newOptions.addAll(options.stream()
.filter(o -> settingName.equalsIgnoringCase(o.getName()))
.collect(Collectors.toList());
Then the failing assertion will alert you to the null value. By switching the equalsIgnoringCase the code will filter out null names rather than throwing an exception.
Related
I am calling two methods in reactive style.
Mono<OrderPublicDto> order = orderWebClient.getOrderById(orderID, bearerToken);
Mono<DriverDto> driver = order.flatMap(o -> vehicleWebClient.getDriverById(o.getDriverId(), bearerToken));
I need to make it so that if truckID from order (OrderPublicDto) == null, DriverDto empty is returned in the second method.
How can I do it right?
Simply use the filter operator to return an empty Mono in this scenario:
orderWebClient.getOrderById(orderID, bearerToken)
.filter(o -> o.getTruckID() != null)
.flatMap(o -> vehicleWebClient.getDriverById(o.getDriverId(), bearerToken)));
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.
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();
Starting with a bean class MyBean with a single relevant propterty:
#Data
class MyBean {
private String myProperty;
}
Now I have got a set of these beans Set<MyBean> mySet usually with 0, 1, or 2 elements.
The question is: How do I retrieve myProperty from this set if it is equal for all elements, or else null. Preferably in a single line with effort O(n).
I found several examples to determine the boolean if all properties are equal. But I want to know the corresponding property.
Is there something smarter than this?
String uniqueProperty = mySet.stream().map(MyBean::getMyProperty).distinct().count() == 1
? mySet.stream().map(MyBean::getMyProperty).findAny().orElse(null)
: null;
Your version is already O(n).
It's possible to do this with a one-liner (although yours is too depending on how you write it).
String uniqueProperty = mySet.stream()
.map(MyBean::getMyProperty)
.map(Optional::ofNullable)
.reduce((a, b) -> a.equals(b) ? a : Optional.empty()) // Note: equals compares 2 Optionals here
.get() // unwraps first Optional layer
.orElse(null); // unwraps second layer
The only case this doesn't work for is when all property values are null. You cannot distinguish the set (null, null) from (null, "A") for example, they both return null.
Just a single iteration without the use of streams looks much better for such a use case :
Iterator<MyBean> iterator = mySet.iterator();
String uniqueProperty = iterator.next().getMyProperty();
while (iterator.hasNext()) {
if (!iterator.next().getMyProperty().equals(uniqueProperty)) {
uniqueProperty = null; // some default value possibly
break;
}
}
You use the findAny() first and check mySet again with allMatch() to require all items to match the first one in a filter():
String uniqueProperty = mySet.stream().findAny().map(MyBean::getMyProperty)
.filter(s -> mySet.stream().map(MyBean::getMyProperty).allMatch(s::equals))
.orElse(null);
The advantage of this is, that allMatch() will only evaluate all elements if necessary (docs).
I'm getting
java.lang.NullPointerException: Attempt to invoke virtual method
'float java.lang.Number.floatValue()' on a null object reference
on following code:
val localHistory: ArrayList<Float> = ArrayList<Float>()
...
val strHistory = localHistory.map { value -> decoration.decoratedValue(ref.format, value) }
I've just learned that ArrayList may contain nulls (oookay). That would mean that the value in the map transforming closure may be NULL, no?
But this cannot be since the value is not an optional type and the compiler says that if (value != null) will be always true.
So the question is how to avoid NPE in this case?
I suggest marking every parameter in a Collection you receive from Java as nullable (unless of course you know it can never be null:
val floats: List<Float?> = someJavaClass.getFloats()
Then you can filter out the nulls and do your map operation:
val newFloats: List<Float> = floats
.filter { it != null }
.map { it + 1 }
Keep in mind that every filter, map (and so on) operation will iterate the whole collection and create a new on everytime. You're better of using Sequences, which are iterated lazily.
As mentioned in the comments one may use filterNotNull to directly filter out all null values:
val newFloats: List<Float> = floats
.filterNotNull()
.map { it + 1 }
And mapNotNull to only keep values which map-function doesn't return null, this also eliminates the filterNotNull:
val newFloats: List<Float> = floats
.mapNotNull { it?.plus(1) }
Another construct I can think of which works with your example though it is highly unreadable and just complex. But here it is:
val strHistory = localHistory
.mapNotNull { decoration.decoratedValue(ref.format, it ?: return#mapNotNull null) }
If you just want to exclude the null values in the ArrayList, call mapNotNull instead of map. See here for details.
You then also need to handle the case where the value is null inside your lambda, which you can do with the ?.let as shown below:
localHistory.mapNotNull { value -> value?.let { decoration.decoratedValue(ref.format, it) } }
One more with mapNotNull:
val strHistory = localHistory.mapNotNull { it ?: return#mapNotNull null
decoration.decoratedValue(ref.format, it) }
I have the following snippet that collects specific objects which have a name string property that contains a specific filter filterName.
List<Foo> filteredFoo= fooList.stream()
.filter(Objects::nonNull)
.filter(myFoo -> {
if (Strings.isNullOrEmpty(myFoo.getName()))
return false;
return myFoo.getName().contains(filterName);
}
).collect(Collectors.toList());
It works as expected but I was wondering whether is there a more elegant way to write the if-statement in a functional way and check for empty or null properties in a nicer fashion than having the conditional block in the filter.
Replace second filter with following:
.filter(myFoo -> Optional.ofNullable(myFoo.getName())
.filter(n -> n.contains(filterName))
.isPresent())
or even:
.filter(myFoo -> {
String name = myFoo.getName();
return name != null && name.contains(filterName)
})
Go for the functional style, for the result expression:
.filter(foo -> foo.getName() != null && foo.getName().contains(filterName))
Splitting would not bring more simplicity:
.filter(foo -> foo.getName() != null)
.filter(foo -> foo.getName().contains(filterName))
Using predicates on Foo::getName (Objects::isNull) is senseless complicated too, just in order to spare a variable.
If filterName is not empty itself, Strings.isEmptyOrNull is not needed.
If you have access to Foo Class then move the if conditions to a method isSameName and use filter as below
filter(myFoo -> {return myFoo.isSameName(filterName);})