NPE when using map {} on ArrayList containing NULLs - java

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) }

Related

How can i set a generic List as a property in a Neo4j stored procedure?

I am making a Neo4j plugin with some stored procedures. One of these needs to take arguments of arbitrary type, and save them as properties on a Node. Naïvely I might do it like this
val props: Map<String, Any> = <procedure input>
props.forEach(node::setProperty)
This works fine for scalar types, but if the value is a List it fails with
java.lang.IllegalArgumentException: [[123]:java.util.ArrayList] is not a supported property value
since setProperty wants the value to be an Array. Simply casting the List to an Array results in an Array<Any> due to (I assume) type erasure.
I have this slightly clunky solution:
props.forEach { (key, value) ->
if (value is Collection<*>) {
val firstElement = value.firstOrNull()
if (firstElement != null) {
val arrayValue: Array<Any?> =
java.lang.reflect.Array.newInstance(firstElement.javaClass, value.size) as Array<Any?>
value.forEachIndexed { index, element -> arrayValue[index] = element }
node.setProperty(key, arrayValue)
} else {
node.setProperty(key, emptyArray<Long>()) // Arrays need a type, so we just pick one
}
} else {
node.setProperty(key, value)
}
}
This works, but is there an easier way to do what I want?
Kotlin already has inbuilt function toTypedArray() . It will convert any collection to array without losing the type. Hope this is what you need.
var value = arrayListOf<String>("Foo","Bar")
var arrayValue : Array<String> = value.toTypedArray()
This is a part of Kotlin Standard Library. You can find latest version here.

Filter out null values in Java 8 stream filter expression so exception is not thrown

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

Get unique Object from a Stream if present

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).

How to parallelize a loop in Java

In the following code, a local method is called on every element of a HashSet. If it returns a special value we halt the loop. Otherwise we add every return value to a new HashSet.
HashSet<Object> myHashSet=…;
HashSet<Object> mySecondHashSet=…;
for (Object s : myHashSet) {
Object value = my_method(s);
if(value==specialValue)
return value;
else
mySecondHashSet.add(value);
}
I’d like to parralelize this process. None of the objects in the HashSet have any objects in common (it’s a tree-like structure) so I know they can run without any synchonization issues. How do I modify the code such that each call of my_method(s) starts a new tread, and also that if one of the threads evaluates to the special values, all the threads halt without returning and the special value is returned?
Having in mind java 8, this could be relatively simple, while it won't preserve your initial code semantics:
In case all you need is to return special value once you hit it
if (myHashSet.parallelStream()
.map(x -> method(x))
.anyMatch(x -> x == specialValue)) {
return specialValue;
}
If you need to keep transformed values until you meet the special value, you already got an answer from #Elliot in comments, while need to mention that semantic is not the same as your original code, since no orderer will be preserved.
While it yet to be checked, but I would expect following to be optimized and stop once it will hit wanted special value:
if (myHashSet.parallelStream()
.anyMatch(x -> method(x) == specialValue)) {
return specialValue;
}
I would do that in two passes:
find if any of the transformed set elements matches the special value;
transform them to a Set.
Starting a new thread for each transformation is way too heavy, and will bring your machine to its knees (unless you have very few elements, in which case parallelizing is probably not worth the effort.
To avoid transforming the values twice with my_method, you can do the transformation lazily and memoize the result:
private class Memoized {
private Object value;
private Object transformed;
private Function<Object, Object> transform;
public Memoized(Object value, Function<Object, Object> transform) {
this.value = value;
}
public Object getTransformed() {
if (transformed == null) {
transformed = transform.apply(value);
}
return transformed;
}
}
And then you can use the following code:
Set<Memoized> memoizeds =
myHashSet.stream() // no need to go parallel here
.map(o -> new Memoized(o, this::my_method))
.collect(Collectors.toSet());
Optional<Memoized> matching = memoized.parallelStream()
.filter(m -> m.getTransformed().equals(specialValue))
.findAny();
if (matching.isPresent()) {
return matching.get().getTransformed();
}
Set<Object> allTransformed =
memoized.parallelStream()
.map(m -> m.getTransformed())
.collect(Collectors.toSet());

Getting NullPointerException while using Lambda expression

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.

Categories

Resources