Collection là cấu trúc dữ liệu lưu trữ (in-memory data structure). Stream là pipeline xử lý dữ liệu (computation pipeline). Khác biệt bản chất: "Lưu trữ" vs "Xử lý".
Bảng so sánh
| Tiêu chí | Collection | Stream |
|---|---|---|
| Mục đích | Lưu trữ & thao tác dữ liệu (add, remove, get, iterate) | Xử lý dữ liệu (filter, map, reduce, collect) – không lưu trữ |
| Package | java.util.* (List, Set, Queue, Map...) | java.util.stream.* (Stream, IntStream...) |
| Evaluation | Eager – tính toán ngay khi add/put | Lazy – intermediate ops không chạy cho đến terminal op |
| Modification | Có thể add/remove/clear | Không thể sửa đổi (read-only view) |
| Iteration | External iteration (client dùng for/iterator) | Internal iteration (Stream quản lý loop) |
| Reusability | Dùng nhiều lần | Chỉ dùng 1 lần (terminal op consume stream) |
| Parallelism | Khó (phải tự manage thread) | Dễ dàng: .parallelStream() |
| Storage | Chứa elements | Không chứa elements – chỉ reference source |
Ví dụ Collections
import java.util.*;
public class CollectionDemo {
public static void main(String[] args) {
List laptops = new ArrayList<>();
laptops.add("HCL"); laptops.add("Apple"); laptops.add("Dell");
// External iteration
for (String s : laptops) System.out.println(s);
// Sort (mutates original list)
laptops.sort(Comparator.naturalOrder());
System.out.println("Sorted: " + laptops);
}
}
Ví dụ Streams
import java.util.*;
import java.util.stream.*;
public class StreamDemo {
public static void main(String[] args) {
List laptops = Arrays.asList("HCL", "Apple", "Dell", "HP", "Lenovo");
// Internal iteration, lazy, không mutate original
List filtered = laptops.stream()
.filter(s -> s.length() <= 4) // Intermediate (lazy)
.map(String::toUpperCase) // Intermediate (lazy)
.sorted() // Intermediate (stateful, lazy)
.collect(Collectors.toList()); // Terminal (eager) – trigger execution
System.out.println("Original: " + laptops); // Unchanged
System.out.println("Filtered: " + filtered); // [DELL, HP]
// Parallel processing dễ dàng
long count = laptops.parallelStream()
.filter(s -> s.contains("L"))
.count();
System.out.println("Count with 'L': " + count);
}
}
Quan hệ: Collection → Stream → Collection
Collectionsource = ...; Stream stream = source.stream(); // Collection → Stream List result = stream.collect(toList()); // Stream → Collection (terminal)
Stream không thay thế Collection. Chúng bổ sung nhau: Collection lưu trữ, Stream xử lý.
Khi nào dùng cái nào?
- Collection: Cần lưu trữ, truy cập ngẫu nhiên (get(index)), add/remove thường xuyên, duyệt nhiều lần, thread-safe container (ConcurrentHashMap).
- Stream: Xử lý dữ liệu once-through: filter/map/reduce, pipeline phức tạp, parallel processing, functional style, chuyển đổi dữ liệu (ETL), không cần lưu trung gian.
Lưu ý hiệu năng
- Stream có overhead object creation (lambda, spliterator) – không dùng cho loop đơn giản, hot path.
- Parallel stream chỉ nhanh khi: dataset lớn, CPU-intensive, stateless ops, đủ core.
- Primitive streams (
IntStream, LongStream, DoubleStream) tránh boxing/unboxing – nhanh hơn nhiều cho số.