Study guide

8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing

Oracle Java SE 17 Developer Certified Professional 1Z0-829

Track your progress as you read

Finished sections get a check mark.

1 Introduction: The 1Z0-829 Exam

About the Java SE 17 Developer (1Z0-829) Exam

2 Chapter 1: Java Fundamentals & Language Basics

1.1 Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting 1.2 Local Variable Type Inference (`var`) Rules and Scoping 1.3 Operators, Precedence, Evaluation Order, and Short-Circuit Evaluation 1.4 Text Blocks, String Immutability, and StringBuilder APIs

3 Chapter 2: Program Flow & Decision Constructs

2.1 Conditional Branching with if/else and the Ternary Operator 2.2 Switch Statements and Switch Expressions 2.3 Iteration Constructs, Loop Control, and Branching Labels

4 Chapter 3: Object-Oriented Design & Class Mechanics

3.1 Class Declarations, Field/Method Signatures, and Access Modifiers 3.2 Constructors, Overloading, Initialization Order, and Garbage Collection 3.3 Inheritance, Method Overriding, Polymorphism, and `super`/`this` 3.4 Abstract Classes, Static Members, and Object Methods (`equals`, `hashCode`, `toString`)

5 Chapter 4: Advanced OOP: Interfaces, Records & Sealed Types

4.1 Interface Architecture: Default, Static, and Private Methods 4.2 Enumerations: Constants, Constructors, Methods, and Custom Bodies 4.3 Records: Canonical/Compact Constructors, Components, and Immutability 4.4 Sealed Classes and Interfaces: `permits`, Hierarchy Constraints, and Modifiers

6 Chapter 5: Pattern Matching & Nested Types

5.1 Pattern Matching for `instanceof` and Flow Scoping Mechanics 5.2 Nested Types: Member Inner, Static Nested, Local, and Anonymous Classes 5.3 Defensive Programming, Immutability Patterns, and Validation

7 Chapter 6: Generics, Collections & Arrays

6.1 Generic Classes, Interfaces, Methods, and Type Erasure 6.2 Bounded Type Parameters and Wildcards (PECS Rule) 6.3 Collections Framework: List, Set, Queue, and Deque APIs 6.4 The Map Interface, Sorting, Comparable, and Comparator 6.5 Arrays: Declaration, Initialization, Multidimensional Arrays, and the Arrays Utility Class

8 Chapter 7: Functional Programming & Lambda Expressions

7.1 Functional Interfaces and Lambda Syntax Rules 7.2 Standard Functional Interfaces in `java.util.function` 7.3 Method References: Static, Bound, Unbound, and Constructor References

9 Chapter 8: The Stream API

8.1 Stream Lifecycle: Creation, Pipeline Architecture, and Lazy Evaluation 8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing 8.3 Terminal Stream Operations: Reduction, Matching, Finding, and Collecting 8.4 Primitive Streams (`IntStream`, `LongStream`, `DoubleStream`) and Numeric Statistics

10 Chapter 9: Advanced Streams & Collectors

9.1 The Optional Class: Safe Null Handling, Transformation, and Chaining 9.2 The Collectors API: Downstream Reductions, Grouping, and Partitioning 9.3 Parallel Streams: Fork/Join Pool, Spliterators, and Concurrency Pitfalls

11 Chapter 10: Exception Handling

10.1 The Java Exception Hierarchy: Checked vs. Unchecked Exceptions and Errors 10.2 Exception Constructs: `try-catch-finally`, Multi-Catch, and Rethrowing 10.3 Try-With-Resources, `AutoCloseable`, Suppressed Exceptions, and Custom Exceptions

12 Chapter 11: Date/Time API & Localization

11.1 Date and Time Core Types: `LocalDate`, `LocalTime`, `LocalDateTime` 11.2 Timestamps, Intervals, and Durations: `Instant`, `Period`, and `Duration` 11.3 Time Zones, Daylight Saving Time (DST) Offsets, and `ZonedDateTime` 11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters 11.5 Formatting and Parsing Messages, Numbers, Percentages, and Localized Dates

13 Chapter 12: Java Platform Module System (JPMS)

12.1 Module Architecture, `module-info.java`, and Module Paths 12.2 Module Directives: `requires`, `requires transitive`, `exports`, and Qualified Exports 12.3 Reflection, Deep Encapsulation, `opens`, and Open Modules 12.4 Services in JPMS (`uses`, `provides...with`), Migration Paths, and Tooling (`jlink`, `jdeps`) 12.5 Compiling and Packaging Code: Non-Modular JARs, Modular JARs, and Migration Strategies

14 Chapter 13: Concurrency & Multithreading

13.1 Thread Fundamentals, `Runnable`, `Callable`, and Thread Lifecycle 13.2 Memory Visibility, `volatile`, Intrinsic Locks, and Synchronization 13.3 The Concurrency Framework: `ExecutorService`, Thread Pools, and `Future` 13.4 Concurrent Collections, Atomic Variables, Explicit Locks, and `CompletableFuture`

15 Chapter 14: Java I/O and NIO.2

14.1 Classical I/O: Byte and Character Streams, Readers, Writers, and Buffering 14.2 Object Serialization, `Serializable`, `transient`, and `serialVersionUID` 14.3 NIO.2 Architecture: `Path`, `Paths`, and Basic `Files` Operations 14.4 Advanced NIO.2: Directory Walking, Streams (`Files.lines`, `walk`), and `WatchService`

16 Chapter 15: Accessing Databases with JDBC

15.1 JDBC Architecture, Drivers, `DriverManager`, and `DataSource` Connections 15.2 SQL Execution: `Statement`, `PreparedStatement`, and `CallableStatement` 15.3 `ResultSet` Navigation, Data Types, and Transaction Management (Commit, Rollback, Savepoints)

17 Chapter 16: Annotations & the Java Logging API

16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs 16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration

8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing

Key Takeaways Explain This Topic AI

Intermediate operations return a new stream instance and are classified as either stateless (processing elements independently, e.g., filter, map, flatMap) or stateful (retaining historical state, e.g., distinct, sorted, limit, skip).

map(Function) performs 1-to-1 element transformation, whereas flatMap(Function) performs 1-to-many transformation by flattening nested streams into a single composite stream.

distinct() removes duplicate elements using Object.equals() and hashCode(), while sorted() orders elements by Comparable natural ordering or an explicit Comparator.

takeWhile(Predicate) short-circuits upon the first false predicate evaluation, whereas dropWhile(Predicate) discards elements until the first false predicate evaluation and then emits all remaining elements.

peek(Consumer) is intended exclusively for non-intrusive debugging; modifying external state inside peek violates non-interference, and the JVM may elide peek calls when stream sizes are pre-calculated.

Last updated: October 2026

8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing

Intermediate operations form the transformation stages of a stream pipeline. Every intermediate operation transforms an input stream into a new output stream, enabling declarative method chaining. Because intermediate operations are lazily evaluated, they act as descriptive blueprints for data manipulation. Java categorizes intermediate operations into stateless and stateful operations based on their internal memory requirements and parallel processing semantics.

Stateless vs. Stateful Intermediate Operations

Understanding the distinction between stateless and stateful operations is critical for performance tuning and predicting pipeline behavior:

Stateless Operations : Each element is processed independently without retaining state or knowledge of previously evaluated elements. Stateless operations require O ( 1 ) O(1) O ( 1 ) auxiliary memory and parallelize effortlessly across CPU cores.

Examples : filter , map , mapToInt , flatMap , peek .

Stateful Operations : Processing an element requires retaining historical state from previously encountered elements or buffering the entire stream before yielding downstream elements. Stateful operations may need to buffer elements ( sorted and distinct can hold the whole stream, roughly O ( n ) O(n) O ( n ) memory) or track position ( limit , skip ), and they add coordination cost in parallel streams.

Examples : distinct , sorted , limit , skip , takeWhile , dropWhile .

Warning

The Stateful Sorting Barrier on Infinite Streams The sorted() operation is stateful and non-short-circuiting: it cannot emit a single sorted element until it has examined and buffered every element from upstream. Invoking sorted() on an infinite stream (e.g., Stream.iterate(1, n -> n + 1).sorted().limit(5) ) creates an infinite loop that eventually crashes the JVM with OutOfMemoryError: Java heap space . To sort an infinite stream, the short-circuiting operation must precede sorting: .limit(5).sorted() .

  • Filtering and Element Transformation
  • filter(Predicate<? super T>)

The filter operation evaluates each upstream element against a Predicate . If the predicate returns true , the element passes downstream; if false , the element is dropped: List<String> names = List.of("Brian", "Alice", "Bob", "Alexander");

  • List<String> longNames = names.stream()
  • .filter(s -> s.length() > 5)
  • .toList(); // [Alexander]
  • map(Function<? super T, ? extends R>)

The map operation performs a one-to-one transformation. For every input element of type T , it applies the Function and emits exactly one element of type R downstream: List<String> words = List.of("Java", "Stream", "API");

  • List<Integer> lengths = words.stream()
  • .map(String::length) // Transforms Stream<String> into Stream<Integer>
  • .toList(); // [4, 6, 3]
  • flatMap(Function<? super T, ? extends Stream<? extends R>>)

The flatMap operation performs a one-to-many transformation. Each input element is mapped to an independent Stream<R> , and flatMap flattens all of these individual streams into a single, unified Stream<R> : List<List<String>> nested = List.of(

  • List.of("Spring", "Hibernate"),
  • List.of("Micronaut", "Quarkus"),
  • List.of("Helidon")
  • );
  • // Flattening nested collections
  • List<String> frameworks = nested.stream()
  • .flatMap(Collection::stream) // Flattens Stream<List<String>> into Stream<String>
  • .map(String::toUpperCase)
  • .toList();
  • // [SPRING, HIBERNATE, MICRONAUT, QUARKUS, HELIDON]

flatMap is indispensable when unwrapping complex structures, such as splitting sentences into words ( sentence -> Arrays.stream(sentence.split(" ")) ) or unpacking nested Optional references.

  • Duplicate Elimination and Sorting
  • distinct()

The distinct() method removes duplicate elements from the stream. Uniqueness is determined strictly according to Object.equals(Object) and Object.hashCode() : List<Integer> nums = List.of(1, 2, 2, 3, 3, 3, 4);

List<Integer> unique = nums.stream().distinct().toList(); // [1, 2, 3, 4]

For custom domain classes, failing to properly override both equals() and hashCode() prevents distinct() from identifying duplicate objects.

sorted() and sorted(Comparator<? super T>)

Java provides two sorting operations:

sorted() : Sorts elements according to their natural ordering . Elements must implement Comparable<? super T> .

sorted(Comparator<? super T>) : Sorts elements according to an explicit Comparator . List<String> cities = List.of("Paris", "Tokyo", "Berlin", "Cairo");

  • // Natural order (alphabetical)
  • List<String> natural = cities.stream().sorted().toList();
  • // [Berlin, Cairo, Paris, Tokyo]
  • // Custom comparator (descending length)
  • List<String> byLengthDesc = cities.stream()
  • .sorted(Comparator.comparingInt(String::length).reversed())
  • .toList();
  • // [Berlin, Paris, Tokyo, Cairo]

Warning

The ClassCastException on sorted() Due to generic type erasure, calling the no-argument sorted() method on a stream of objects that do not implement Comparable compiles without error. However, when the terminal operation executes, the JVM attempts to cast the elements to Comparable , throwing a runtime ClassCastException: class CustomType cannot be cast to class java.lang.Comparable .

  • Stream Slicing Operations
  • limit(long maxSize) and skip(long n)

limit(maxSize) : Truncates the stream to at most maxSize elements. It is a short-circuiting stateful operation.

skip(n) : Discards the first n elements and emits all subsequent elements. List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

  • List<Integer> middle = numbers.stream()
  • .skip(3) // Discards 1, 2, 3
  • .limit(4) // Retains 4, 5, 6, 7
  • .toList();
  • Java 9 Slicing: takeWhile(Predicate) vs. dropWhile(Predicate)

Introduced in Java 9, takeWhile and dropWhile provide conditional slicing based on predicate evaluation along the stream's encounter order:

takeWhile(Predicate<? super T>) : Takes elements from the beginning of the stream as long as the predicate evaluates to true . The moment an element evaluates to false , takeWhile immediately terminates and short-circuits , dropping that element and all remaining elements regardless of whether later elements satisfy the predicate.

dropWhile(Predicate<? super T>) : Discards elements from the beginning of the stream as long as the predicate evaluates to true . The moment an element evaluates to false , dropWhile stops dropping and emits that element and all remaining downstream elements without testing the predicate ever again. List<Integer> values = List.of(2, 4, 6, 7, 8, 10, 12);

  • // takeWhile stops at first odd number (7)
  • List<Integer> taken = values.stream()
  • .takeWhile(n -> n % 2 == 0)
  • .toList(); // [2, 4, 6]
  • // dropWhile drops until first odd number (7), then emits everything else
  • List<Integer> dropped = values.stream()
  • .dropWhile(n -> n % 2 == 0)
  • .toList(); // [7, 8, 10, 12]

Method Behavior on Ordered Stream Short-Circuiting?

  • filter(p) Evaluates all elements; keeps every element matching p . No
  • takeWhile(p) Takes contiguous matching prefix; stops at first non-matching element. Yes
  • dropWhile(p) Drops contiguous matching prefix; emits first non-match and all subsequent elements. No

Note

On unordered streams (e.g., from HashSet.stream() ), takeWhile and dropWhile are non-deterministic: the subset of elements taken or dropped depends on arbitrary iteration order.

Side-Effect Inspection with peek(Consumer<? super T>)

The peek operation applies a Consumer to each element as it passes through the pipeline, returning an identical stream. It is designed strictly for diagnostic logging and debugging : List<String> result = Stream.of("one", "two", "three", "four")

  • .filter(e -> e.length() > 3)
  • .peek(e -> System.out.println("Filtered value: " + e))
  • .map(String::toUpperCase)
  • .peek(e -> System.out.println("Mapped value: " + e))
  • .toList();
  • The peek Anti-Pattern and Optimization Caveat

Using peek to mutate program state or execute business logic is a dangerous anti-pattern:

Non-interference violation : Modifying shared mutable state inside peek causes race conditions in parallel pipelines.

Optimization Elision (Java 9+) : When the terminal operation does not require element values to compute its result (e.g., count() on a stream source of known size), the JVM implementation is permitted to skip intermediate operations entirely , meaning peek will never execute! // In Java 9+, the JVM knows the exact size from Stream.of() and may optimize count():

long count = Stream.of("a", "b", "c")

.peek(System.out::println) // Might NOT be printed!

.count();