Remove Null Values in Java
Problem
A List can hold null as a valid element, so removing nulls means explicitly filtering them out rather than relying on them being absent by default.
Given a List that may contain null entries, remove every one of them.
Java Program
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class RemoveNullValues {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
list.add(null);
list.add("Banana");
list.add(null);
list.add("Cherry");
list.removeIf(Objects::isNull); // deletes every element the predicate matches
System.out.println(list);
}
}Output
Core Logic
Passing removeIf() a condition that matches null values deletes every one of them from the list in a single call, without a manual loop.
- 1
list.removeIf(Objects::isNull)passesObjects.isNullas the predicate — a method reference equivalent to writingx -> x == null. - 2
removeIf()walks the list internally and deletes every element for which the predicate returnstrue. - 3Every non-null element keeps its relative order, since only the null entries are removed.
- 4The list is modified in place — there's no separate result list to collect.
[Apple, null, Banana, null, Cherry], both null entries are removed, leaving [Apple, Banana, Cherry].Key Point: Objects::isNull is a method reference, not a call — it's passed to removeIf() as the function to run on each element, the same shape as a lambda like x -> x == null would be.
Why: removeIf() checks every one of the n elements against the predicate exactly once, modifying the list in place with no extra storage.
Key Concepts
Approach 2: Java 8
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class RemoveNullValuesStream {
public static void main(String[] args) {
List<String> list = new java.util.ArrayList<>();
list.add("Apple");
list.add(null);
list.add("Banana");
list.add(null);
list.add("Cherry");
// Keeps only non-null elements, collected into a brand new list
List<String> cleaned = list.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
System.out.println(cleaned);
}
}
Output
Core Logic
Filtering the stream down to only the non-null elements and collecting the result builds a fresh, null-free list instead of mutating the original in place.
- 1
list.stream()opens a stream over the original list, including itsnullentries. - 2
.filter(Objects::nonNull)keeps only the elements that aren'tnull. - 3
.collect(Collectors.toList())gathers the surviving elements into a brand new List. - 4Unlike
removeIf(), the original list is never modified — a separate, filtered list is produced instead.
[Apple, null, Banana, null, Cherry] for non-null elements and collecting the result gives [Apple, Banana, Cherry], the same values the in-place version ends up with.Key Point: This is a genuinely different behavior from removeIf(), not just a different syntax for the same thing — the stream version leaves the original list (nulls included) completely untouched and returns a new one, which matters if other code still holds a reference to the original list.
Why: filter() still checks each of the n elements once, and collect() builds a new list to hold the surviving non-null elements, unlike removeIf()'s in-place O(1)-extra-space mutation.