VieTopik
Tiếng HànTiếng Anh.NET (C#)Java
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
Java CoreCông cụ hằng ngày
Bài 17/19
5 phút

Stream cơ bản

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 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()) cho sorted biết cần xếp tăng dần theo giá.
  • toList() gom kết quả thành List.
  • String.join(", ", names) ghép các phần tử thành một chuỗi.
filter: stock > 0 sorted: price map: name products: Bút bi, Vở, Balo Bút bi, Balo Bút bi 5000, Balo 350000 names: Bút bi, Balo
Dữ liệu đi qua từng bước của stream

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
false

Là 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ọi toList() để 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ùng orElse thay vì get().

Tự kiểm tra

0/3 câu
Câu 1

List<Integer> nums = List.of(5, 2, 8); int r = nums.stream().sorted().findFirst().get(); Giá trị của r là gì?

Câu 2

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?

Câu 3

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?

LambdaException

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt