Module Review: Streams & Lambdas

[!NOTE] This module explores the core principles of Module Review: Streams & Lambdas, deriving solutions from first principles and hardware constraints to build world-class, production-ready expertise.

1. Key Takeaways

  1. Declarative Style: Java 8 introduced functional programming to write code that focuses on what to do (filter, map) rather than how to loop.
  2. Lambdas & Interfaces: Lambda expressions (args) → body are concise implementations of Functional Interfaces (interfaces with a single abstract method).
  3. Stream Pipeline: A stream consists of a Source, zero or more Intermediate Operations (lazy), and a Terminal Operation (eager).
  4. Lazy Evaluation: Intermediate operations (like filter, map) do not execute until a terminal operation (like collect, forEach) is invoked.
  5. Parallelism: parallelStream() uses the ForkJoinPool to split tasks across threads. It is beneficial for large datasets or CPU-intensive tasks (NQ > 10,000) but adds overhead for small tasks.
  6. No Boxing: Use IntStream, LongStream, or DoubleStream to avoid the memory overhead of boxing primitives into Objects.

2. Interactive Flashcards

Test your recall of the core concepts. Click or press Space/Enter to flip.

?

What is a Functional Interface?

!

An interface with exactly one abstract method. It can be implemented by a Lambda Expression.

?

Is filter() intermediate or terminal?

!

Intermediate. It returns a new Stream and is lazily evaluated.

?

What happens if you don't call a terminal operation?

!

Nothing! Intermediate operations are lazy and won't execute without a terminal operation to trigger the pipeline.

?

What is the purpose of flatMap()?

!

To flatten nested structures. It transforms each element into a stream of elements, then concatenates them into a single stream.

?

When should you use parallelStream()?

!

When N × Q > 10,000 (Large dataset or expensive operation) and tasks are stateless/independent.

?

What is IntStream?

!

A specialized stream for primitive int values that avoids the overhead of boxing/unboxing Integer objects.

3. Cheat Sheet

Common Functional Interfaces

Interface Signature Usage
Predicate<T> boolean test(T) filter()
Function<T, R> R apply(T) map()
Consumer<T> void accept(T) forEach()
Supplier<T> T get() generate()
UnaryOperator<T> T apply(T) iterate()
BinaryOperator<T> T apply(T, T) reduce()

Stream Operations

Operation Type Description
filter(p) Intermediate Keep elements matching predicate
map(f) Intermediate Transform elements
flatMap(f) Intermediate Flatten nested streams
distinct() Intermediate Remove duplicates
sorted() Intermediate Sort elements
limit(n) Intermediate Truncate stream
peek(c) Intermediate Debug stream (observe elements)
collect(c) Terminal Accumulate into List/Set/Map
forEach(c) Terminal Perform action for each element
reduce(acc) Terminal Combine into single result
count() Terminal Count elements
anyMatch(p) Terminal True if any match (Short-circuit)
findFirst() Terminal Returns Optional<T>

Collectors

Collector Result
toList() List<T>
toSet() Set<T>
joining(del) String
groupingBy(f) Map<K, List<T>>
partitioningBy(p) Map<Boolean, List<T>>
counting() Long

Primitive Streams

Stream Type Usage Benefit
IntStream IntStream.range(0, 100) No Integer boxing
LongStream LongStream.rangeClosed(1, N) 64-bit integers
DoubleStream DoubleStream.of(1.5, 2.0) Floating point

Java Course Glossary

Check the glossary for definitions of all terms used in this module.