ความแตกต่างระหว่าง Intermediate และ Terminal Operations ใน Java 8 Stream API
Stream API ใน Java 8 ใช้สำหรับประมวลผลข้อมูลแบบ Declarative (บอกว่าทำอะไร ไม่ใช่ทำอย่างไร) Operations แบ่งเป็น 2 ประเภทหลัก
Intermediate Operations (ออปเรชันกลาง)
- เปลี่ยน Stream หนึ่งเป็นอีก Stream หนึ่ง (Pipeline)
- Lazy Evaluation: ไม่ทำงานทันที รอ Terminal Operation
- สามารถ Chain ได้หลายตัวต่อเนื่อง
- คืนค่า
Stream<T>
ตัวอย่าง Intermediate Operations
| เมธอด |
คำอธิบาย |
filter(Predicate) |
กรององค์ประกอบตามเงื่อนไข |
map(Function) |
แปลงองค์ประกอบแต่ละตัว
flatMap(Function) |
แบน (flatten) nested streams |
distinct() |
ลบซ้ำ (ใช้ equals/hashCode) |
sorted() / sorted(Comparator) |
เรียงลำดับ |
peek(Consumer) |
ดูค่าแต่ละตัว (debug/logging) |
limit(n) |
จำกัดจำนวน n ตัวแรก |
skip(n) |
ข้าม n ตัวแรก |
Terminal Operations (ออปเรชันปลายทาง)
- ผลิตผลลัพธ์สุดท้าย (Result) หรือ Side-effect
- Eager Evaluation: ทำงานทันที และจบ Stream pipeline
- ไม่สามารถ Chain ต่อได้
- คืนค่า Non-Stream (Collection, Primitive, void, Optional)
ตัวอย่าง Terminal Operations
| เมธอด |
คำอธิบาย |
คืนค่า |
forEach(Consumer) |
วนลูปทำ side-effect |
void |
collect(Collector) |
รวบรวมเป็น Collection |
Collection/List/Set/Map |
toArray() |
แปลงเป็น Array |
Object[] / T[] |
reduce() |
ลดรูปเป็นค่าเดียว |
Optional / T |
count() |
นับจำนวน |
long |
min()/max(Comparator) |
หาค่าต่ำสุด/สูงสุด |
Optional |
anyMatch/allMatch/noneMatch |
ตรวจสอบเงื่อนไข |
boolean |
findFirst()/findAny() |
หาตัวแรก/ตัวไหนก็ได้ |
Optional |
ตารางเปรียบเทียบ
| คุณสมบัติ |
Intermediate |
Terminal |
| การทำงาน |
Lazy (รอ Terminal) |
Eager (ทันที) |
| คืนค่า |
Stream<T> |
Non-Stream (Result) |
| Chain ได้ |
✅ ได้หลายตัว |
❌ จบ Pipeline |
| Short-circuit |
บางตัว (limit, findFirst) |
บางตัว (anyMatch, findFirst) |
ตัวอย่าง Pipeline สมบูรณ์
import java.util.*;
import java.util.stream.*;
public class StreamDemo {
public static void main(String[] args) {
List laptops = Arrays.asList("DELL", "ACER", "HCL", "ASUS", "LENOVO");
// Pipeline: Intermediate -> Intermediate -> Terminal
List result = laptops.stream()
.filter(s -> s.length() > 3) // Intermediate: filter
.map(String::toLowerCase) // Intermediate: transform
.sorted() // Intermediate: sort
.peek(s -> System.out.println("Processing: " + s)) // Intermediate: peek
.collect(Collectors.toList()); // Terminal: collect
System.out.println("Result: " + result);
}
}
ผลลัพธ์
Processing: acer
Processing: asus
Processing: dell
Processing: hcl
Processing: lenovo
Result: [acer, asus, dell, hcl, lenovo]
ข้อสังเกตสำคัญ
- Lazy Evaluation: Intermediate ops ไม่ทำงานจนกว่าจะมี Terminal op
- Short-circuiting:
limit(), findFirst() หยุดเร็วเมื่อได้ผล
- Stateless vs Stateful: filter/map stateless (เร็ว), sorted/distinct stateful (ต้องดูทั้งหมด)
- Parallel Streams: ใช้
.parallelStream() แทน .stream() สำหรับข้อมูลมาก