Quiz 2

Streams API & Lambda Expressions

1019 words
5 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Streams API & Lambda Expressions ## 🎯 Learning Objectives - Write lambda expressions for functional interfaces - Use the Stream API for declarative data processing - Chain intermediate and terminal stream operations - Understand Optional for null-safe code - Compare Java streams with Python comprehensions ## 1. L...

Streams API & Lambda Expressions

🎯 Learning Objectives

  • Write lambda expressions for functional interfaces
  • Use the Stream API for declarative data processing
  • Chain intermediate and terminal stream operations
  • Understand Optional for null-safe code
  • Compare Java streams with Python comprehensions

1. Lambda Expressions — Passing Behavior

1.1 The Problem

Before Java 8, passing behavior required verbose anonymous inner classes:
java
// Pre-Java 8 — verbose
Collections.sort(list, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return a.length() - b.length();
    }
});

1.2 Lambda Solution

java
// Java 8+ — concise
Collections.sort(list, (a, b) -> a.length() - b.length());
Lambda syntax:
pseudo
(parameters) -> expression
(parameters) -> { statements; }

1.3 Lambda Variants

java
// Zero parameters
() -> System.out.println("Hello")
// One parameter (parens optional)
x -> x * x
// Multiple parameters
(a, b) -> a + b
// Multiple statements
(a, b) -> {
    int sum = a + b;
    System.out.println(sum);
    return sum;
}

1.4 Functional Interfaces (SAM — Single Abstract Method)

java
@FunctionalInterface
interface Calculator {
    int operate(int a, int b);
}
// Usage:
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;
System.out.println(add.operate(5, 3));     // 8
System.out.println(multiply.operate(5, 3)); // 15
Built-in functional interfaces:
InterfaceMethodSignature
Predicatetest(T)T → boolean
Functionapply(T)T → R
Consumeraccept(T)T → void
Supplierget()() → T
UnaryOperatorapply(T)T → T
BinaryOperatorapply(T,T)(T,T) → T

2. Method References

Shorthand when lambda just calls an existing method:
java
// Lambda
list.forEach(s -> System.out.println(s));
// Method reference
list.forEach(System.out::println);
// Other forms:
String::length          // instance method on arbitrary object
"Hello"::length        // instance method on specific object
Math::sqrt              // static method
String::new             // constructor
new int[5]::clone       // constructor reference for arrays

3. Stream API

3.1 Creating Streams

java
// From collections
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();
// From arrays
Stream<Integer> arrStream = Arrays.stream(new Integer[]{1, 2, 3});
// From values
Stream<String> of = Stream.of("A", "B", "C");
// Infinite streams
Stream<Integer> evens = Stream.iterate(0, n -> n + 2);
Stream<Double> randoms = Stream.generate(Math::random);

3.2 Intermediate Operations (Lazy)

java
List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
// filter — keep elements matching predicate
words.stream()
     .filter(s -> s.length() > 5)
     .forEach(System.out::println);  // banana, cherry, elderberry
// map — transform each element
words.stream()
     .map(String::toUpperCase)
     .forEach(System.out::println);  // APPLE, BANANA, ...
// flatMap — flatten nested streams
List<List<Integer>> nested = Arrays.asList(
    Arrays.asList(1, 2), Arrays.asList(3, 4, 5));
nested.stream()
      .flatMap(Collection::stream)
      .forEach(System.out::println);  // 1, 2, 3, 4, 5
// distinct, sorted, peek, limit, skip
words.stream()
     .filter(s -> s.startsWith("a"))
     .map(String::toUpperCase)
     .sorted()
     .limit(2)
     .forEach(System.out::println);

3.3 Terminal Operations (Eager)

java
// collect — accumulate into collection
List<String> result = words.stream()
    .filter(s -> s.length() > 4)
    .collect(Collectors.toList());
// reduce — combine elements
int sum = Arrays.asList(1, 2, 3, 4, 5).stream()
    .reduce(0, (a, b) -> a + b);  // 15
// counting, groupingBy, partitioningBy
Map<Integer, List<String>> byLength = words.stream()
    .collect(Collectors.groupingBy(String::length));
// findFirst, findAny, allMatch, anyMatch, noneMatch
boolean hasLongWord = words.stream().anyMatch(s -> s.length() > 10);

3.4 Stream Pipeline Pattern

java
int result = numbers.stream()          // Source
    .filter(n -> n % 2 == 0)           // Intermediate (lazy)
    .map(n -> n * n)                   // Intermediate (lazy)
    .sorted(Comparator.reverseOrder()) // Intermediate (lazy)
    .findFirst()                       // Terminal (eager)
    .orElse(0);                        // Terminal result

4. Optional — Null Safety

java
// Before Optional — null-prone
String name = findName(id);
if (name != null) {
    System.out.println(name.toUpperCase());
}
// With Optional
Optional<String> optional = findNameOptional(id);
optional.map(String::toUpperCase)
        .ifPresent(System.out::println);
// Creating Optional
Optional<String> empty = Optional.empty();
Optional<String> nonNull = Optional.of("Hello");  // NullPointerException if null
Optional<String> nullable = Optional.ofNullable(maybeNull);
// Operations
optional.isPresent()           // boolean check
optional.ifPresent(System.out::println)  // consume if present
optional.orElse("default")     // value or default
optional.orElseGet(() -> expensiveDefault())  // lazy default
optional.orElseThrow(() -> new NotFoundException())  // or throw
optional.map(String::length)    // transform if present
optional.filter(s -> s.length() > 5)  // filter if present

5. Java vs Python

FeatureJavaPython
Lambda(x) -> x * xlambda x: x * x
Filter.filter(pred)filter(func, iter)
Map.map(func)map(func, iter)
Reduce.reduce(identity, op)reduce(func, iter)
List comp.collect(Collectors.toList())[x*2 for x in list]
Lazy streamsYes (intermediate ops are lazy)Yes (generators, itertools)
Null safetyOptionalOptional[T] (external lib)

6. Practice Questions

Q1: What is the output?
java
List<String> words = Arrays.asList("cat", "dog", "bird", "fish");
words.stream()
     .filter(w -> w.length() > 3)
     .map(String::toUpperCase)
     .forEach(System.out::println);
Answer: BIRD FISH (cat and dog have length ≤ 3) Q2: Difference between intermediate and terminal operations?
Answer: Intermediate operations (filter, map, sorted) are lazy — they don't execute until a terminal operation is called. Terminal operations (forEach, collect, reduce) trigger the pipeline and produce a result or side effect. Q3: What does Optional.of(null) do?
Answer: Throws NullPointerException. Use Optional.ofNullable(null) if the value might be null. Q4: Write a lambda that squares a number and add it to a method.
java
Function<Integer, Integer> square = x -> x * x;
System.out.println(square.apply(5));  // 25
Q5: What is a method reference and when to use it?
Answer: A method reference (ClassName::method) is shorthand for a lambda that calls an existing method. Use it when the lambda body is just a single method call: s -> s.length() becomes String::length. Q6: Can a stream be reused after a terminal operation?
Answer: No. After a terminal operation, the stream is consumed. Calling another operation on it throws IllegalStateException. Create a new stream for each pipeline. Q7: What does Collectors.groupingBy do?
Answer: Groups elements by a classifier function, producing a Map<K, List<V>>:
java
Map<Integer, List<String>> byLen = words.stream()
    .collect(Collectors.groupingBy(String::length));
Q8: What is the difference between map and flatMap?
Answer: map transforms each element (1-to-1). flatMap transforms each element into a stream, then flattens all streams (1-to-many-to-flat). Example: split strings into words.

📐 Key Concepts

FeaturePurposeExample
LambdaAnonymous function(x, y) -> x + y
StreamDeclarative data processinglist.stream().filter(...).map(...).collect(...)
OptionalNull-safe containersOptional.ofNullable(val).orElse(default)
Method refLambda shorthandString::length
CollectorAccumulate stream → collectionCollectors.toList()

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.