Back to Stream: filter
Q10Question 10 of 19

Filter employees whose email domain is "gmail.com"

Key Concepts
  • Use String.endsWith("@gmail.com") to check the domain, including the @ sign to avoid false matches.
  • Without the @ sign, an address like someone@notgmail.com would wrongly match a plain gmail.com suffix.
  • Splitting on @ and comparing index 1 with equalsIgnoreCase is more precise for case-insensitive matching.
  • Always guard against null emails with a null check first, relying on short-circuit evaluation.
  • Pattern.compile(regex).asPredicate() or asMatchPredicate() converts a regex to a reusable Predicate.
  • For anything beyond a simple domain check, use a vetted library for full email validation.
  • Email domains are case-insensitive by RFC standard, so lower-case or use equalsIgnoreCase.

Definition

Filter on endsWith("@gmail.com") including the @ sign to avoid false matches like notgmail.com, and guard against null with short-circuit evaluation.
  • endsWith("@gmail.com") – checks the domain portion including the @ to prevent false positives.
  • Split approach – email.split("@")[1].equalsIgnoreCase("gmail.com") is more precise for case-insensitive matching.
  • Null guard – e.email() != null && e.email().endsWith(...) uses short-circuit to avoid NPE.
  • Case sensitivity – email domains are case-insensitive by RFC, so lower-case before comparing or use equalsIgnoreCase.
  • Regex alternative – Pattern.compile(".*@gmail\\.com$").asPredicate() for pattern-based matching.

The compliance officer at National Bank of India says, 'List every employee who registered a personal Gmail address so we can remind them to use the official bank email.' The clerk checks each address and keeps the ones ending in @gmail.com.

Understanding the Concepts

How do you filter by email domain?

JAVA
package com.bank.service;

import java.util.List;

public class EmailDomainFilter {
    record Employee(String name, String email) {}

    public static void main(String[] args) {
        List<Employee> staff = List.of(
            new Employee("Rajesh", "rajesh@gmail.com"),
            new Employee("Priya", "priya@bank.co.in"),
            new Employee("Amit", "amit@Gmail.COM"),
            new Employee("Deepa", null),
            new Employee("Vikram", "vikram@notgmail.com")
        );

        List<Employee> gmailUsers = staff.stream()
            .filter(e -> e.email() != null
                      && e.email().toLowerCase().endsWith("@gmail.com"))
            .toList();

        gmailUsers.forEach(e -> System.out.println(e.name() + ": " + e.email()));
    }
}
TEXT
Rajesh: rajesh@gmail.com
Amit: amit@Gmail.COM

Vikram's email is vikram@notgmail.com which does not end with @gmail.com because the @ anchors the domain boundary. Deepa's null email is safely skipped by the null check.

Why must you include the @ sign?

JAVA
// WRONG: without @ sign, notgmail.com matches
"vikram@notgmail.com".endsWith("gmail.com"); // true! False positive!

// CORRECT: with @ sign, only exact domain matches
"vikram@notgmail.com".endsWith("@gmail.com"); // false
"rajesh@gmail.com".endsWith("@gmail.com");     // true

How do you use the split approach?

JAVA
staff.stream()
    .filter(e -> {
        if (e.email() == null) return false;
        String[] parts = e.email().split("@");
        return parts.length == 2 && parts[1].equalsIgnoreCase("gmail.com");
    })
    .toList();

Splitting is more precise: it isolates the domain part and compares case-insensitively. It also catches malformed emails (missing @ or multiple @ signs).

How do you use Pattern for regex-based filtering?

JAVA
import java.util.regex.Pattern;
import java.util.function.Predicate;

// Compile once, reuse the predicate (thread-safe)
Predicate<String> isGmail = Pattern.compile("(?i).*@gmail\\.com$").asPredicate();

List<Employee> result = staff.stream()
    .filter(e -> e.email() != null && isGmail.test(e.email()))
    .toList();

The (?i) flag makes the regex case-insensitive. Compile the pattern once and reuse the predicate for performance.

What is the comparison of approaches?

| Approach | Pros | Cons |
|----------|------|------|
| endsWith("@gmail.com") | Simple, fast | Case-sensitive unless you lower-case |
| split("@") + equalsIgnoreCase | Precise, case-insensitive | Slightly more code |
| Pattern.asPredicate() | Flexible, handles complex patterns | Regex overhead, harder to read |

What are common mistakes?

JAVA
// WRONG: no null guard
staff.stream().filter(e -> e.email().endsWith("@gmail.com")); // NPE on null!

// CORRECT: null check first with short-circuit
staff.stream().filter(e -> e.email() != null && e.email().endsWith("@gmail.com"));

// WRONG: missing @ prefix
staff.stream().filter(e -> e.email().endsWith("gmail.com")); // false positives!

// CORRECT: include @ sign
staff.stream().filter(e -> e.email().endsWith("@gmail.com"));

What are edge cases?

  • Null email: guarded by the null check before any method call.
  • Upper-case domain: Amit@GMAIL.COM must be matched case-insensitively.
  • Subdomain: someone@mail.gmail.com does not end with @gmail.com; split approach handles this.
  • Multiple @ signs: malformed addresses like user@@gmail.com are caught by the split approach.
  • Empty email string: "".endsWith("@gmail.com") returns false, which is correct.

What should a senior engineer know?

  • Email domains are case-insensitive by RFC 5321; always lower-case or use equalsIgnoreCase.
  • For full email validation (not just domain check), use a vetted library like Apache Commons Validator.
  • In banking compliance, scanning for personal email domains is a real security audit task.
  • Pattern compilation is expensive; compile once and reuse. The resulting Predicate is thread-safe.

Visual Overview

DIAGRAM
  Email domain filter:
  ────────────────────
  Input: rajesh@gmail.com      endsWith("@gmail.com") → true  ✓
  Input: priya@bank.co.in      endsWith("@gmail.com") → false ✗
  Input: amit@Gmail.COM        toLowerCase → @gmail.com → true  ✓
  Input: null                  null check → skip       ✗
  Input: vikram@notgmail.com   endsWith("@gmail.com") → false ✗
                               (@ anchors the boundary)
  Result: [Rajesh, Amit]

Key Takeaway

To filter by email domain, use endsWith with the full suffix including the @ sign. Without the @, an address at notgmail.com would wrongly match. Guard against null emails with a null check first, relying on short-circuit evaluation.

Email domains are case-insensitive by RFC standard, so lower-case the address before comparing or use equalsIgnoreCase. The split approach isolates the domain part precisely and handles edge cases like malformed addresses.

For complex pattern matching, Pattern.compile().asPredicate() converts a regex to a reusable, thread-safe Predicate. For anything beyond a simple domain check, use a vetted library for full email validation.

Remember one sentence: include the @ sign in endsWith to anchor the domain boundary, guard against null, and lower-case for case-insensitive matching.

---

Share
Use ← → arrow keys to navigate