filter and map
Keep what you want with filter, reshape it with map, and chain the two safely.
Open this lesson in the learning hubKey points
filtertakes a Predicate and keeps whatever passes. The count can shrink; elements never change.maptakes a Function and swaps each element for something else. The count stays the same.- Method references such as
Book::titleread better thanb -> b.title(). - Filter first, then map. Transforming elements you are about to discard is wasted work.
- Keep lambdas pure: no printing, no field updates, no touching the source collection.
Example
import java.util.*;
public class Main {
record Book(String title, String genre, int pages) {}
public static void main(String[] args) {
List<Book> books = List.of(
new Book("Dune", "scifi", 412),
new Book("Neuromancer", "scifi", 271),
new Book("Emma", "classic", 474));
// filter keeps or drops. It never changes an element.
List<Book> scifi = books.stream().filter(b -> b.genre().equals("scifi")).toList();
// map transforms. Exactly one out for every one in.
List<String> titles = books.stream().map(Book::title).toList();
System.out.println("scifi count : " + scifi.size());
System.out.println("titles : " + titles);
System.out.println("page counts : " + books.stream().map(Book::pages).toList());
System.out.println("chained : " + books.stream()
.filter(b -> b.pages() > 300)
.map(b -> b.title().toUpperCase())
.toList());
}
}
filter changes how many; map changes what.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Streams course, and every lesson in it is listed on the Streams contents page.