How to handle null values in Java Streams?

Introduction

In this blog we will learn how to handle null values while using streams.

At the end of this blog you will know how to create null safe streams.

The collection which is processed can itself by null or elements inside the collections can also null.

If we do not handle properly we will get NullPointerException which can be avoided.

Streams NullPointerException

In the below example if we process null list using Streams we get NullPointerException.

We need to check whether the input itself is null.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package com.examples;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {

        List<Integer> nums = null;
        List<Integer> result = nums.stream().map(x -> x * 3).collect(Collectors.toList());
        System.out.println(result);

    }
}

Output:

1
2
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.util.List.stream()" because "nums" is null
at com.examples.App.main(App.java:12)

Handling null conditions for the Streams

If we are not sure whether we will get non empty collection or null we should use Optional.ofNullable(nums).

Optional.ofNullable(nums) check if the collection is empty or not.

If empty it executes orElse condition by returning empty collection as specfied in it.

If collection is not null, it is further processed.

In the below example, input list is null and output is an empty list, not NullPointerException

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.examples;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;

public class App {

    public static void main(String[] args) {

       // List<Integer> nums = Arrays.asList(10,null,30,40,50);
        List<Integer> nums = null;

        List<Integer> result = Optional.ofNullable(nums)
                .orElse(Collections.emptyList());

        System.out.println(result); // [] --> Not a NullPointerException



    }
}

In the below example, input list is not null and it is processed further based on the logic.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package com.examples;

import java.util.*;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {

         List<Integer> nums = Arrays.asList(10,20,30,40,50);

        List<Integer> result = Optional.ofNullable(nums)
                .orElse(Collections.emptyList())
                 .stream()
                 .map(x -> x* 2)
                 .collect(Collectors.toList());

         System.out.println(result); //[20, 40, 60, 80, 100]

    }
}

Handling null check for elements processed in the stream

In this scenario some of the elements processed by the stream itself is null.

In the below example one the element in the list is null.

In the map method it will give NullPointerException.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package com.examples;

import java.util.*;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {

         List<Integer> nums = Arrays.asList(10,null,30,40,50);

        List<Integer> result = Optional.ofNullable(nums)
                .orElse(Collections.emptyList())
                 .stream()
                  .map(x -> x* 2)
                  .collect(Collectors.toList());

         System.out.println(result); //[20, 40, 60, 80, 100]
    }
}

Output

1
2
3
4
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "x" is null
at com.examples.App.lambda$main$0(App.java:15)
...
at com.examples.App.main(App.java:16)

To handle this we need to introduce null check before mapping it.

We need to filter element which are not null and pass it on to the map method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package com.examples;

import java.util.*;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {

         List<Integer> nums = Arrays.asList(10,null,30,40,50);

        List<Integer> result = Optional.ofNullable(nums)
                .orElse(Collections.emptyList())
                .stream()
                .filter(Objects::nonNull) // .filter(x -> x!=null)
                 .map(x -> x* 2)
                 .collect(Collectors.toList());

         System.out.println(result); //[20, 60, 80, 100]
    }
}

Handling objects in stream for preventing NullPointerException

Let us take a real use case of Employee object which is having a Set of hobbies.

Some of the hobbies in the list are null.

By implementing what we have learnt above, let us process incoming employee objects in the streams without any NullPointerException

Below Employee class has set of hobbies

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Employee {

    private int empId;
    private String empName;
    private Set<String> hobbies;

    public Employee(int empId, String empName, Set<String> hobbies) {
        this.empId = empId;
        this.empName = empName;
        this.hobbies = hobbies;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Set<String> getHobbies() {
        return hobbies;
    }

    public void setHobbies(Set<String> hobbies) {
        this.hobbies = hobbies;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "empId=" + empId +
                ", empName='" + empName + '\'' +
                ", hobbies=" + hobbies +
                '}';
    }
}

In the below example we can see, for employee id 3 we have passed null as hobbies.

Below code handles for null hobbies inside the employee object by using .filter(x-> x.getHobbies()!=null)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.examples;

import java.util.*;
import java.util.stream.Collectors;

public class App {

    public static void main(String[] args) {

        List<Employee> names = new ArrayList<>();

        Set<String> hobbies1 = new HashSet<>();
        hobbies1.add("playing");
        hobbies1.add("music");

        Set<String> hobbies2 = new HashSet<>();
        hobbies2.add("reading");
        hobbies2.add("cricket");

        names.add(new Employee(1,"Tim",hobbies1));
        names.add(new Employee(2,"Jim",hobbies2));
        names.add(new Employee(3,"Mary",null));


        Set<String> result = Optional.ofNullable(names)  // handle for null inputs
                .orElse(Collections.emptyList()) // return empty list if null
                .stream() // process further for non empty list
                .filter(x-> x.getHobbies()!=null) // filter non empty hobbies
                .map(x -> x.getHobbies())
                .flatMap(Set::stream)     // flattening Set<> into single Set
                .collect(Collectors.toSet());

        System.out.println(result);  // [music, cricket, reading, playing]
    }
}

Conclusion

Just we have seen how to handle null collections and null elements inside the collections in streams using various examples.

I hope this will help you to write error free and robust code while handling streams.