Back to Stream: filter
Q15Question 15 of 19

Filter out null or empty employee names from the list

Key Concepts
  • Two bad states to reject: null (absent reference) and blank (empty or whitespace-only string).
  • Test null first with short-circuit AND to avoid NullPointerException on subsequent method calls.
  • Java 11 isBlank() is cleaner than trim().isEmpty() for detecting whitespace-only strings.
  • Predicate.not(String::isBlank) is the cleanest way to filter non-blank strings in Java 11+.
  • Objects::nonNull filters nulls from a stream of raw references before further processing.
  • A reusable StringUtils.isNotBlank utility or Apache Commons provides consistent null/blank handling.
  • Data cleansing filters are always the first step before any business logic in banking data pipelines.

Definition

Keep only names that are not null and not blank by checking non-null first (short-circuit), then non-empty, using isBlank() on Java 11+ or trim().isEmpty() on Java 8.
  • Null – an absent reference; calling any method on it throws NullPointerException.
  • Blank – an empty string or a string of only whitespace; technically a valid object but useless as a name.
  • Order – null check must come first in the AND chain; short-circuit prevents the second check from executing on null.
  • isBlank() – Java 11 method that returns true for empty and whitespace-only strings without explicit trim.
  • Predicate.not() – Java 11 static method for clean negation: filter(Predicate.not(String::isBlank)).

The HR clerk at National Bank of India is cleaning the staff list before printing. Some entries have no name at all (null) and some have just empty spaces. She throws those away and keeps only the real names. That cleanup is the filter.

Understanding the Concepts

How do you filter out null and blank names?

JAVA
package com.bank.service;

import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;

public class NullBlankFilter {
    record Employee(String name, String department) {}

    public static void main(String[] args) {
        List<Employee> staff = List.of(
            new Employee("Rajesh", "IT"),
            new Employee("", "Finance"),
            new Employee("   ", "HR"),
            new Employee("Priya", "IT")
        );
        // Note: null names would require a mutable list or different construction

        // Java 11+: isBlank() handles empty and whitespace-only
        List<Employee> clean = staff.stream()
            .filter(e -> e.name() != null && !e.name().isBlank())
            .toList();

        clean.forEach(e -> System.out.println("'" + e.name() + "'"));
    }
}
TEXT
'Rajesh'
'Priya'

The empty string and the whitespace-only string are both rejected.

Why must the null check come first?

JAVA
// WRONG: method call on null throws NPE
names.stream().filter(n -> !n.isBlank() && n != null); // NPE if n is null!

// CORRECT: null check first, short-circuit prevents method call on null
names.stream().filter(n -> n != null && !n.isBlank());

Java short-circuits the AND: if n != null is false, !n.isBlank() is never evaluated.

What is the difference between isEmpty and isBlank?

| Method | Empty string "" | Whitespace " " | "Rajesh" |
|--------|:---:|:---:|:---:|
| isEmpty() | true | false | false |
| isBlank() (Java 11) | true | true | false |
| trim().isEmpty() (Java 8) | true | true | false |

isBlank() treats whitespace-only strings as blank without needing an explicit trim.

How do you use Predicate.not for cleaner syntax?

JAVA
import java.util.function.Predicate;

// For a List<String> of raw names:
List<String> names = List.of("Rajesh", "", "   ", "Priya");

// Java 11+: Predicate.not is the cleanest
List<String> clean = names.stream()
    .filter(Predicate.not(String::isBlank))
    .toList();
// ["Rajesh", "Priya"]

Predicate.not reads as 'filter: not blank' and is cleaner than n -> !n.isBlank().

How do you handle null elements in the stream itself?

JAVA
import java.util.Arrays;
import java.util.Objects;

List<String> names = Arrays.asList("Rajesh", null, "", "Priya", null, "   ");

// Step 1: remove nulls with Objects::nonNull
// Step 2: remove blanks with Predicate.not(String::isBlank)
List<String> clean = names.stream()
    .filter(Objects::nonNull)
    .filter(Predicate.not(String::isBlank))
    .toList();
// ["Rajesh", "Priya"]

What are common mistakes?

JAVA
// WRONG: no null guard
names.stream().filter(n -> !n.isBlank()); // NPE on null elements!

// CORRECT: null guard first
names.stream().filter(n -> n != null && !n.isBlank());

// WRONG: using isEmpty when whitespace should be rejected
names.stream().filter(n -> n != null && !n.isEmpty()); // keeps "   "

// CORRECT: using isBlank to reject whitespace
names.stream().filter(n -> n != null && !n.isBlank());

What about a reusable utility predicate?

JAVA
public class StringPredicates {
    public static Predicate<String> isNotBlank() {
        return s -> s != null && !s.isBlank();
    }
}

// Usage across the codebase
names.stream().filter(StringPredicates.isNotBlank()).toList();

Apache Commons provides StringUtils.isNotBlank() for the same purpose.

What are edge cases?

  • Null reference: guarded by the null check; short-circuit prevents NPE.
  • Empty string "": isBlank returns true, filtered out.
  • Whitespace only " ": isBlank returns true, filtered out.
  • Tab and newline "\t\n": isBlank returns true, filtered out.
  • Single space " ": isBlank returns true, filtered out.
  • Valid name with leading spaces " Rajesh ": isBlank returns false, kept. Use trim() or strip() afterward if needed.

What should a senior engineer know?

  • Data cleansing filters are always the first step in banking data pipelines before any business logic.
  • Extract the null/blank check into a reusable utility so the rule is defined once and consistent everywhere.
  • In Java 11+, prefer isBlank() over trim().isEmpty() for clarity and intent.
  • strip() (Java 11) handles Unicode whitespace better than trim() for international banking data.

Visual Overview

DIAGRAM
  Null/Blank filter pipeline:
  ──────────────────────────
  Input: ["Rajesh", null, "", "   ", "Priya", null]
       │
  filter(Objects::nonNull)
       │
  ["Rajesh", "", "   ", "Priya"]
       │
  filter(Predicate.not(String::isBlank))
       │
  ["Rajesh", "Priya"]

  isBlank truth table:
  ─────────────────────
  null     → NPE (guard first!)
  ""       → true  (empty)
  "   "    → true  (whitespace only)
  "Rajesh" → false (has content)

Key Takeaway

Filtering null and blank values requires two checks in the right order: null first, then blank. Java short-circuits the AND, so the null check prevents NullPointerException on the subsequent method call. isBlank() (Java 11) handles both empty and whitespace-only strings without explicit trim.

For the cleanest syntax, use filter(Objects::nonNull).filter(Predicate.not(String::isBlank)) which reads as 'filter: not null, then not blank.' Extract this into a reusable utility predicate because the same null/blank check appears throughout any codebase.

Data cleansing is always the first step in banking data pipelines. Before any business logic runs, remove null and blank entries so downstream code does not need defensive checks everywhere.

Remember one sentence: null check first with short-circuit, then isBlank() for empty and whitespace, and extract into a reusable utility predicate.

---

Share
Use ← → arrow keys to navigate