Tổng kết module — Stream API & Lambda
Recap toàn module: cheat-sheet, glossary, pitfall checklist, và self-assessment 1-1 với 5 learning outcomes. Dùng để ôn trước khi chuyển module tiếp theo.
TL;DR: Module Stream API & Lambda dạy cách xử lý dữ liệu theo functional style trong Java — từ lambda & method reference (building block), stream pipeline lazy (cơ chế cốt lõi), collectors & optional (terminal nâng cao), đến parallel stream & immutability (production concerns). Bài này là recap + self-assessment để kiểm tra xem bạn thực sự nắm trước khi tiếp tục.
Hành trình qua module
Bạn vừa đi qua 10 bài concept + mini-challenge:
- Lambda & Functional Interface — SAM type,
@FunctionalInterface, 4 built-in cốt lõi (Predicate,Function,Consumer,Supplier) - Method Reference & invokedynamic — 4 loại method ref, cơ chế
invokedynamicbytecode, tại sao không slower than lambda - Stream basics — lazy pipeline, intermediate vs terminal, element-by-element, short-circuit
- map / filter / reduce — 3 op cốt lõi, reduce nontrivial, chaining
- Stream nâng cao —
flatMap,distinct,sorted,takeWhile/dropWhile,peek - Optional — NPE-safe chaining,
map/flatMap/orElse/orElseThrow - Collectors deep —
groupingBy,partitioningBy,joining, downstream collector, custom Collector - Parallel Stream — ForkJoinPool, khi nào parallel win/lose, thread-safety,
Spliterator - Immutability & Functional Style — value object, pure function, compose pipeline
- Mini-challenge Sales Report — tổng hợp toàn bộ
Cheat-sheet
Phân loại operation
| Loại | Ví dụ | Return type | Lazy? |
|---|---|---|---|
| Intermediate stateless | filter, map, flatMap, peek | Stream<T> | Có |
| Intermediate stateful | sorted, distinct, skip | Stream<T> | Có (buffer) |
| Intermediate short-circuit | limit(n), takeWhile | Stream<T> | Có |
| Terminal eager | collect, forEach, reduce, count, toList | non-Stream | Không |
| Terminal short-circuit | findFirst, findAny, anyMatch, allMatch, noneMatch | non-Stream | Không |
Nguồn stream thường dùng
| Nguồn | Cách tạo | Hữu hạn? |
|---|---|---|
| Collection | list.stream() | Có |
| Array | Arrays.stream(arr) | Có |
| Factory | Stream.of(a, b, c), Stream.empty() | Có |
| Int range | IntStream.range(0, n), IntStream.rangeClosed(1, n) | Có |
| Infinite generator | Stream.iterate(seed, fn), Stream.generate(supplier) | Không — cần limit |
| File | Files.lines(path) trong try-with-resources | Có (EOF) |
Functional interface mapping
| Interface | Method | Dùng trong |
|---|---|---|
Predicate<T> | boolean test(T t) | filter, anyMatch, noneMatch |
Function<T,R> | R apply(T t) | map, flatMap |
Consumer<T> | void accept(T t) | forEach, peek |
Supplier<T> | T get() | Stream.generate, orElseGet |
UnaryOperator<T> | T apply(T t) | Stream.iterate |
BinaryOperator<T> | T apply(T t1, T t2) | reduce |
Comparator<T> | int compare(T a, T b) | sorted, min, max |
Glossary
| Thuật ngữ | Định nghĩa ngắn |
|---|---|
| Lazy evaluation | Intermediate op không chạy cho đến khi có terminal op kích hoạt |
| Pipeline | Chuỗi op xâu chuỗi nhau: stream().op1().op2()...terminal() |
| Short-circuit | Op dừng sớm khi đủ kết quả — không duyệt hết stream |
| Stateful intermediate | Op phải buffer trước khi emit (sorted, distinct) |
| Sink | Interface nội bộ JDK nhận element từ upstream stage; terminal op wires các Sink thành chuỗi khi pipeline khởi động |
| Loop Fusion | JDK gộp nhiều intermediate op thành 1 lượt duyệt qua Sink chain |
| Spliterator | Interface bên dưới Stream để traverse source; hỗ trợ split cho parallel |
| Optional | Container 0-hoặc-1 giá trị, tránh NPE khi return |
| Collector | Recipe cho terminal op collect() — cách gom element thành kết quả |
| ForkJoinPool | Thread pool dùng cho parallelStream() — work-stealing |
| Pure function | Không side-effect, output chỉ phụ thuộc input — safe cho stream |
Pitfall checklist
Trước khi merge code dùng Stream, kiểm tra từng mục này (xem chi tiết tại Stream basics và Parallel Stream):
- Quên terminal op —
stream.filter(...)không có.toList()hay.forEach(...)→ không chạy gì - Reuse stream — dùng stream sau khi đã có terminal op →
IllegalStateException sorted()trên infinite stream — hang forever; dùnglimitTRƯỚCsortedpeekcho logic chính — Java 9+ có thể skippeektrên stream SIZED; dùngforEach- Modify collection gốc trong lambda —
forEach(x -> list.add(...))→ConcurrentModificationException limitTRƯỚCsorted— thứ tự op ảnh hưởng kết quả;limit(3).sorted()khácsorted().limit(3)parallelvới stateful lambda — chia sẻ mutable state giữa thread → race conditionparallelvới I/O —parallelStream()dùng ForkJoinPool common; blocking I/O chặn pool- NPE từ
Optional.get()— dùngorElseThrow()hoặcisPresent()check trước
✅ Self-assessment
Bạn đã đạt module này nếu trả lời được 5 câu sau (match 1-1 với learning outcomes):
- Explain được cơ chế lazy evaluation — tại sao intermediate op chỉ ghi ý định và terminal op mới kích hoạt pipeline, và hệ quả với stream vô hạn và short-circuit
- Implement được stream pipeline với
filter/map/reduce/collecttrên collection lẫn infinite source — không cần nhìn tài liệu - Choose được đúng functional interface (
Predicate,Function,Consumer,Supplier) và viết method reference tương ứng cho từng stream op - Diagnose được pitfall stream phổ biến: missing terminal op, stream reuse
IllegalStateException, stateful op trên infinite stream - Compare được imperative loop vs functional stream về readability, memory, và short-circuit behaviour
Module tiếp theo: khi bạn tick được cả 5 ô trên, bạn sẵn sàng cho Java Internals — JVM memory model, GC, concurrency, và performance tuning.
Bài này có giúp bạn hiểu bản chất không?
Hỏi đáp về bài này
Chưa có câu hỏi
Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).
Đặt câu hỏi đầu tiên