40. Checking null references in functional style and imperative code

Independent of functional style or imperative code, checking null references is a common and recommended technique used for mitigating the occurrence of famous NullPointerException exception. This kind of checking is heavily exploited for method arguments to ensure that the passing references will not cause NullPointerException or unexpected behavior.

For example, passing List<Integer> to a method may require at least two null checks. First, the method should ensure that the list reference itself is not null. Second, depending on how the list is used, the method should ensure that the list does not contain null objects:

List<Integer> numbers 
= Arrays.asList(1, 2, null, 4, null, 16, 7, null);

This list is passed to the following method:

public static List<Integer> evenIntegers(List<Integer> integers) {

if (integers == null) {
return Collections.EMPTY_LIST;
}

List<Integer> evens = new ArrayList<>();
for (Integer nr: integers) {
if (nr != null && nr % 2 == 0) {
evens.add(nr);
}
}

return evens;
}

Notice that the preceding code uses the classical checks relying on the == and != operators (integers==null, nr !=null). Starting with JDK 8, the java.util.Objects class contains two methods that wrap the null checks based on these two operators: object == null was wrapped in Objects.isNull(), and object != null was wrapped in Objects.nonNull().

Based on these methods, the preceding code can be rewritten as follows:

public static List<Integer> evenIntegers(List<Integer> integers) {

if (Objects.isNull(integers)) {
return Collections.EMPTY_LIST;
}

List<Integer> evens = new ArrayList<>();

for (Integer nr: integers) {
if (Objects.nonNull(nr) && nr % 2 == 0) {
evens.add(nr);
}
}

return evens;
}

Now, the code is somehow more expressive, but this is not the main usage of these two methods. Actually, these two methods have been added for another purpose (conforming to API notes)—to be used as predicates in the Java 8 functional style code. In functional style code, the null checks can be accomplished as in the following examples:

public static int sumIntegers(List<Integer> integers) {

if (integers == null) {
throw new IllegalArgumentException("List cannot be null");
}

return integers.stream()
.filter(i -> i != null)
.mapToInt(Integer::intValue).sum();
}

public static boolean integersContainsNulls(List<Integer> integers) {

if (integers == null) {
return false;
}

return integers.stream()
.anyMatch(i -> i == null);
}

It is quite obvious that i -> i != null and i -> i == null are not expressed in the same style with the surrounding code. Let's replace these snippets of code with Objects.nonNull() and Objects.isNull():

public static int sumIntegers(List<Integer> integers) {

if (integers == null) {
throw new IllegalArgumentException("List cannot be null");
}

return integers.stream()
.filter(Objects::nonNull)
.mapToInt(Integer::intValue).sum();
}

public static boolean integersContainsNulls(List<Integer> integers) {

if (integers == null) {
return false;
}

return integers.stream()
.anyMatch(Objects::isNull);
}

Or, we can use the Objects.nonNull() and Objects.isNull() methods for arguments as well:

public static int sumIntegers(List<Integer> integers) {

if (Objects.isNull(integers)) {
throw new IllegalArgumentException("List cannot be null");
}

return integers.stream()
.filter(Objects::nonNull)
.mapToInt(Integer::intValue).sum();
}

public static boolean integersContainsNulls(List<Integer> integers) {

if (Objects.isNull(integers)) {
return false;
}

return integers.stream()
.anyMatch(Objects::isNull);
}

Awesome! So, by way of conclusion, the functional style code should rely on these two methods whenever the null checks are needed, while in the imperative code, it is a matter of preference.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.168.203