filter & map in Java
Selecting and transforming elements.
.filter(String::isEmpty) to "remove the empty strings". The result contains ONLY empty strings. Who's right about what filter does?The bouncer and the transformer
**filter(predicate) is a bouncer: it keeps** the elements for which the predicate returns true and drops the rest. **map(function) is a transformer: one element in, one element out**, every element converted.
map can change the type
map takes a Function<T, R>, so the output type R can differ from the input. Mapping words to their lengths turns a Stream<String> into a Stream<Integer>.
List<Integer> lengths = words.stream()
.map(String::length) // String→Integer
.toList();Bounce, then transform
What does this print?
List<Integer> r = Stream.of(1, 2, 3, 4, 5, 6)
.filter(n -> n > 3)
.map(n -> n + 100)
.toList();
System.out.println(r);[104, 105, 106][101, 102, 103][4, 5, 6]
Show the answer
[104, 105, 106] — filter keeps 4, 5, 6, then map adds 100 to each survivor.
Does order matter?
On 1, 2, 3: is map(n -> n * 2).filter(n -> n > 4) the same as filter(n -> n > 4).map(n -> n * 2)?
Think about it, then reveal the answer
No! Map first gives 2, 4, 6 → filter keeps [6]. Filter first sees 1, 2, 3 → nothing is > 4 → []. Each operation receives the output of the operation before it.
filter KEEPS, it doesn't remove
This keeps only the empty strings — the opposite of the goal. To keep the non-empty ones, invert the test: **Predicate.not(String::isEmpty)** or s -> !s.isEmpty().
items.stream()
.filter(String::isEmpty) // keeps ""!
.toList();
items.stream()
.filter(Predicate.not(String::isEmpty))
.toList(); // correctThe bread and butter of real code
Most business logic is filter-then-map: active users → their emails, paid orders → their totals. Reviewers watch for inverted predicates (keeping what you meant to drop) — a bug that compiles fine and quietly ships wrong data.
Key takeaways
- filter(pred): keeps elements where pred is true
- map(fn): one output for each input, type may change
- Order matters: each op sees the previous op's output
- Predicate.not(String::isBlank) inverts a method reference
Predicate.not only arrived in Java 11 — before that, flipping a method reference meant writing a lambda like s -> !s.isBlank() by hand.
Practice questions
What does this print?
List<Integer> r = Stream.of(1, 2, 3, 4, 5)
.filter(n -> n % 2 == 1)
.map(n -> n * 10)
.toList();
System.out.println(r);- [20, 40]
- [10, 20, 30, 40, 50]
- [1, 3, 5]
- [10, 30, 50]
Check your answer
[10, 30, 50]. filter keeps the odd numbers 1, 3, 5, then map multiplies each by 10.
What does this print?
List<Integer> r = Stream.of(1, 2, 3, 4)
.map(n -> n * 3)
.filter(n -> n % 2 == 0)
.toList();
System.out.println(r);- [6, 12]
- [2, 4]
- [3, 9]
- [6, 12, 18]
Check your answer
[6, 12]. map runs first, producing 3, 6, 9, 12. filter then keeps the even ones: 6 and 12.