Stream cơ bản
Nội dung bài · 5 mục
- 1.Khái niệm
- 2.Ví dụ
- 3.Thử ngay
- 4.Lỗi hay gặp
- 5.Tóm tắt
Lọc sản phẩm còn hàng, sắp xếp theo giá, lấy tên, tính tổng tiền. Viết bằng
foreach thì mỗi việc tốn năm sáu dòng. Stream làm mỗi việc chỉ trong một
dòng, bằng lambda đã học ở bài trước.
Khái niệm
🔎 Stream: bộ method có sẵn để lọc, sắp xếp, biến đổi và tính toán trên dữ liệu của list, nhận lambda làm điều kiện.
Gọi stream() trên một list để mở stream, rồi nối các method phía sau.
Ví dụ
// Main.java
void main() {
List<Product> products = List.of(
new Product("Bút bi", 5000, 120),
new Product("Vở", 12000, 0),
new Product("Balo", 350000, 8));
List<String> names = products.stream()
.filter(p -> p.getStock() > 0)
.sorted(Comparator.comparingLong(
p -> p.getPrice()))
.map(p -> p.getName())
.toList();
System.out.println(String.join(", ", names));
// Bút bi, Balo
}
// Product.java
class Product {
private String name;
private long price;
private int stock;
public Product(String name, long price, int stock) {
this.name = name;
this.price = price;
this.stock = stock;
}
public String getName() { return name; }
public long getPrice() { return price; }
public int getStock() { return stock; }
}- Các method nối nhau bằng dấu chấm và chạy lần lượt từ trên xuống: lọc còn hàng, xếp theo giá, lấy tên.
Comparator.comparingLong(p -> p.getPrice())chosortedbiết cần xếp tăng dần theo giá.toList()gom kết quả thànhList.String.join(", ", names)ghép các phần tử thành một chuỗi.
Những method dùng nhiều nhất:
| Method | Làm gì |
|---|---|
filter(p -> ...) |
lọc theo điều kiện |
map(p -> ...) |
biến mỗi phần tử thành giá trị khác |
sorted(...) |
sắp xếp theo Comparator |
findFirst() |
lấy phần tử đầu tiên, trả về Optional |
anyMatch(p -> ...) |
có phần tử nào thoả không (boolean) |
count(), mapToLong(...).sum() |
đếm, cộng |
Thử ngay
Giữ nguyên Product.java, trong Main.java thay đoạn từ List<String> names
tới dòng comment bằng:
long inStock = products.stream()
.filter(p -> p.getStock() > 0)
.count();
long stockValue = products.stream()
.mapToLong(p -> p.getPrice() * p.getStock())
.sum();
boolean hasCheap = products.stream()
.anyMatch(p -> p.getPrice() < 1000);
System.out.println(inStock);
System.out.println(stockValue);
System.out.println(hasCheap);Đoán trước khi chạy: inStock là 2 hay 3?
Xem kết quả
2
3400000
falseLà 2, vì "Vở" có stock bằng 0. Tổng giá trị kho là
5000 × 120 + 12000 × 0 + 350000 × 8.
Lỗi hay gặp
Tưởng filter sửa list gốc. Stream không đổi list ban đầu mà trả về kết
quả mới.
// SAI — products vẫn đủ 3 món
products.stream().filter(p -> p.getStock() > 0);
System.out.println(products.size());// ĐÚNG — lưu kết quả vào biến mới
List<Product> available = products.stream()
.filter(p -> p.getStock() > 0)
.toList();
System.out.println(available.size());get() khi không có phần tử nào khớp. findFirst() trả về Optional
rỗng, và get() làm chương trình dừng với NoSuchElementException.
// SAI — lỗi khi chạy: không có món nào trên 1 triệu
Product item = products.stream()
.filter(p -> p.getPrice() > 1000000)
.findFirst()
.get();// ĐÚNG — không có thì nhận giá trị thay thế
String item = products.stream()
.filter(p -> p.getPrice() > 1000000)
.map(p -> p.getName())
.findFirst()
.orElse("Không có");
System.out.println(item);Tóm tắt
- Stream gồm các method như
filter,map,sorted,count, nhận lambda. - Mở bằng
stream(), nối nhiều method bằng dấu chấm, gọitoList()để lấy kết quả dạng list. - Stream không sửa list gốc, muốn dùng kết quả thì lưu vào biến.
findFirst()trả vềOptional. Nếu có thể không tìm thấy, dùngorElsethay vìget().
Tự kiểm tra
0/3 câuList<Integer> nums = List.of(5, 2, 8); int r = nums.stream().sorted().findFirst().get(); Giá trị của r là gì?
Bạn cần danh sách email của mọi khách hàng trong List<Customer> customers. Dùng cách nào?
Chỉ cần biết giỏ hàng có món nào hết hàng hay không. Cách nào hợp lý nhất?