Definition
- 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?
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()));
}
}
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?
// 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?
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?
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?
// 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.COMmust be matched case-insensitively. - Subdomain:
someone@mail.gmail.comdoes not end with@gmail.com; split approach handles this. - Multiple @ signs: malformed addresses like
user@@gmail.comare 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
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.
---