skip to content

What does Optional.filter do, and how does it behave on a present value that fails the predicate?

level: juniorimportance: should knowfreq 52%

answer

  1. filter takes a Predicate (boolean test)
  2. Pass -> same Optional; fail -> empty Optional
  3. Empty in -> predicate skipped, empty out
  4. Failed test == absent for the rest of the chain
  5. Keeps/drops; never transforms the type

basics

~20 s

filter takes a test (predicate). If the Optional has a value and the value passes the test, you keep it; if it fails the test, you get an empty Optional. An already-empty Optional stays empty.

solid answer

~40 s

Optional.filter(Predicate<T>) conditionally keeps or discards the contained value. If the Optional is present and the value satisfies the predicate, filter returns the same Optional unchanged. If the value is present but fails the predicate, it returns an empty Optional. If the Optional was already empty, the predicate is never run and empty is returned. This lets you add a validity condition into an Optional chain without an explicit if — for example .filter(s -> !s.isBlank()) drops blank strings, after which a downstream orElse supplies a default. Because a failed predicate collapses to empty, filter composes cleanly with map, flatMap, orElse, and orElseThrow: a value that fails the test is treated identically to an absent value for the rest of the chain.

go deeper

for a junior

Knows filter keeps the value when the predicate passes and yields empty otherwise.

for a middle

Uses filter to fold a validity condition into a chain and explains the present-but-failing -> empty behavior.

for a senior

Reasons about how filter unifies 'absent' and 'invalid' so the whole chain short-circuits cleanly, and avoids stuffing transformations into it.

for a principal

Treats filter as a declarative guard clause and reviews chains for readability vs an explicit conditional where clearer.

### What filter is for `Optional<T>` holds zero or one value. Sometimes a value is *present* but you only want to keep it if it meets some condition. `filter` lets you express that condition declaratively, inside an `Optional` chain, instead of writing an `if`. ### Signature and a Predicate ```java Optional<T> filter(Predicate<? super T> predicate) ``` A `Predicate<T>` is a functional interface with one method `boolean test(T t)` — it answers a yes/no question about the value. ### The three cases 1. **Empty input** — the predicate is **not** invoked; `filter` returns an empty `Optional`. (No value to test.) 2. **Present and predicate true** — `filter` returns the **same** `Optional`, unchanged. 3. **Present and predicate false** — `filter` returns an **empty** `Optional`. The value is dropped. The key insight is case 3: a present value that *fails* the test becomes **empty**, indistinguishable from "was never there" for the rest of the chain. ### Example ```java Optional<String> input = Optional.of(" "); String name = input .filter(s -> !s.isBlank()) // blank -> empty .orElse("anonymous"); // -> "anonymous" ``` Here the value `" "` is present but blank, so `filter` turns the `Optional` empty, and `orElse` supplies the default. Without `filter`, you would write an explicit `if (input.isPresent() && !input.get().isBlank())`. ### Why it composes well Because both "absent" and "failed the test" are represented the same way (an empty `Optional`), `filter` slots into chains with `map`, `flatMap`, `orElse`, `orElseThrow`, and `ifPresent`: ```java repo.findUser(id) .filter(User::isActive) // drop inactive users .map(User::email) .ifPresent(this::sendWelcome); ``` If the user is missing *or* inactive, nothing downstream runs. ### Edge notes - `filter` never throws for a missing value; it simply skips. - The predicate must handle the actual contained value; since `Optional` cannot contain `null`, you never have to null-check inside the predicate. - `filter` only *keeps or drops* — it never transforms the value's type (that is `map`'s job).

  • Does filter ever throw if the Optional is empty?
    No. On an empty Optional the predicate is not called and an empty Optional is returned; there is no exception.
  • How is a present-but-failing value different from an absent value after filter?
    It is not — both produce an empty Optional, so downstream orElse/orElseThrow/ifPresent treat them identically.

saying these in an interview costs you the question

  • Thinking filter can change the value's type (that is map)
  • Believing filter throws or returns null when the predicate fails — it returns an empty Optional
  • Worrying about null inside the predicate — Optional never holds null

context