I saw in the code patterns like this:
class Train {
Collection passengers = null;
Collection wagons; //by default initialized as null
}
//later in code
if(train.passengers != null) {
train.passengers...
}
We can use the Optional for fluent null logic:
Optional.ofNullable(train.passengers).map(...).orElse(List.of());
The better approach is to avoid null checking by collection initialization:
class Train {
List passengers = new ArrayList();
}
//and later in code
train.passengers.stream().
Yes, more cleaner. No NullPointerException problems. The most important thing is that the code
train.passengers.stream().
will work on non empty collection and also on empty collection! We do not have to check if collection is empty.
Let’s look at another example:
List attributeList = principal.getAttribute(attributeName);
if(Objects.isNull(attributeList) || attributeList.isEmpty()) {
throw new Exception("");
}
principal.getAttribute (attributeName) is from the spring framework:
@Nullable
default <A> List<A> getAttribute(String name) {
return (List)this.getAttributes().get(name);
}
and the documentation is saying:
Returns:
the attribute or null otherwise
The problem is what ‘otherwise’ means. What are the other cases that result in null. We have no clear information here, we need to analyze the code. What if we need to know the reason of null, to return strict info to user/api caller – attribute is not defined, attribute is null, or is empty:
no-attribute, attribute=null, attribute=””
We need to test this method against that cases and check the return values. Ultimately, I think, we will end with extending the framework or writing his own implementation. This is not we want to do, but what to do.
Summary
In most cases you should avoid the collection as null. The code will be cleaner and no NullPointerException problems.
Of course, there will be situations where intentionally null is used to indicate some information/state, but remember, if you must to use the null, use it as a strict/clear case not ‘otherwise’. Here is one example:
Collection addresses = null
... //
//assumption here is that logic before fill the addresses
if (addresses == null) {
throw new RuntimeException("Addresses were not filled!")
}
In this particular case the Optional should be used instead of null
Optional<List> addresses = Optional.empty();
...
if(!addresses.isPresent()) {
throw new RuntimeException("Addresses were not filled!")
}
//or more fluent way
wayPoints.map(addresses -> ...).orElseThrow(() -> new RuntimeException());