Skip to main content

Command Palette

Search for a command to run...

Bài 6: Giới thiệu về Stream trong Java 8

Published
5 min readView as Markdown

Mục tiêu:

  • Giúp người đọc hiểu khái niệm và cách sử dụng Stream trong Java 8.

  • Giải thích các đặc điểm chính của Stream, cách tạo Stream và các thao tác cơ bản trên Stream.

  • Cung cấp ví dụ minh họa chi tiết để áp dụng vào thực tế.


Dàn ý chi tiết:

1. Stream là gì?

Stream là một tính năng mới trong Java 8, giúp xử lý dữ liệu một cách hiệu quả và ngắn gọn hơn. Stream không phải là cấu trúc dữ liệu mà là một API để thao tác trên các tập dữ liệu (như Collection, Array, v.v.).

  1. Đặc điểm của Stream:

    • Lazy evaluation (đánh giá lười): Các thao tác trên Stream chỉ được thực hiện khi cần thiết (khi gọi terminal operation).

    • Không lưu trữ dữ liệu: Stream không lưu trữ dữ liệu, nó chỉ đại diện cho một luồng dữ liệu từ nguồn (source).

    • Không thay đổi dữ liệu gốc: Các thao tác trên Stream không làm thay đổi dữ liệu gốc mà tạo ra một Stream mới.

    • Hỗ trợ thao tác song song (parallel processing): Stream có thể xử lý dữ liệu song song để tăng hiệu suất.

  2. Ví dụ minh họa:

    • Sử dụng Stream để tính tổng các số chẵn trong một danh sách:

        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        int sum = numbers.stream()
                         .filter(n -> n % 2 == 0)
                         .mapToInt(Integer::intValue)
                         .sum();
        System.out.println(sum); // 12
      

2. Tạo Stream

Stream có thể được tạo từ nhiều nguồn khác nhau như Collection, Array, hoặc giá trị tĩnh.

  1. Tạo Stream từ Collection:

    • Sử dụng phương thức stream() hoặc parallelStream():

        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        Stream<String> stream = names.stream();
      
  2. Tạo Stream từ Array:

    • Sử dụng Arrays.stream():

        int[] numbers = {1, 2, 3, 4, 5};
        IntStream stream = Arrays.stream(numbers);
      
  3. Tạo Stream từ giá trị tĩnh:

    • Sử dụng Stream.of():

        Stream<String> stream = Stream.of("Java", "Python", "C++");
      
  4. Tạo Stream từ hàm sinh (Supplier):

    • Sử dụng Stream.generate():

        Stream<Double> randomStream = Stream.generate(Math::random).limit(5);
        randomStream.forEach(System.out::println);
      

3. Các thao tác cơ bản trên Stream

Stream cung cấp hai loại thao tác chính: intermediate operations (thao tác trung gian) và terminal operations (thao tác kết thúc).

  1. Intermediate operations:

    • Là các thao tác trung gian, trả về một Stream mới.

    • Các thao tác này không thực thi ngay mà chỉ được thực thi khi gọi terminal operation.

    • Ví dụ:

      • filter(Predicate<T>): Lọc các phần tử thỏa mãn điều kiện.

          List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
          Stream<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0);
        
      • map(Function<T, R>): Biến đổi từng phần tử.

          List<String> names = Arrays.asList("Alice", "Bob");
          Stream<Integer> nameLengths = names.stream().map(String::length);
        
      • sorted(): Sắp xếp các phần tử.

          List<Integer> numbers = Arrays.asList(5, 3, 1, 4, 2);
          Stream<Integer> sortedNumbers = numbers.stream().sorted();
        
  2. Terminal operations:

    • Là các thao tác kết thúc, trả về kết quả hoặc thực hiện hành động cuối cùng.

    • Sau khi gọi terminal operation, Stream không thể sử dụng lại.

    • Ví dụ:

      • forEach(Consumer<T>): Thực hiện hành động trên từng phần tử.

          List<String> names = Arrays.asList("Alice", "Bob");
          names.stream().forEach(System.out::println);
        
      • collect(Collector<T, A, R>): Thu thập kết quả vào một Collection.

          List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
          List<Integer> evenNumbers = numbers.stream()
                                             .filter(n -> n % 2 == 0)
                                             .collect(Collectors.toList());
        
      • reduce(BinaryOperator<T>): Kết hợp các phần tử thành một giá trị duy nhất.

          List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
          int sum = numbers.stream().reduce(0, Integer::sum);
        

Ví dụ tổng hợp

  1. Sử dụng Stream để lọc và biến đổi dữ liệu:

     List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
     List<String> result = names.stream()
                                .filter(name -> name.length() > 4) // Lọc tên có độ dài > 4
                                .map(String::toUpperCase)         // Chuyển đổi thành chữ in hoa
                                .collect(Collectors.toList());    // Thu thập kết quả
     System.out.println(result); // [ALICE, CHARLIE, DAVID]
    
  2. Sử dụng Stream để tính tổng các số chẵn:

     List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
     int sum = numbers.stream()
                      .filter(n -> n % 2 == 0) // Lọc số chẵn
                      .mapToInt(Integer::intValue) // Chuyển đổi thành IntStream
                      .sum(); // Tính tổng
     System.out.println(sum); // 12
    

Tổng kết

  • Stream là một API mạnh mẽ trong Java 8, giúp xử lý dữ liệu một cách hiệu quả và ngắn gọn.

  • Stream có hai loại thao tác chính: intermediate operations (thao tác trung gian) và terminal operations (thao tác kết thúc).

  • Hiểu rõ cách tạo và sử dụng Stream là nền tảng để áp dụng các tính năng nâng cao như Parallel StreamCollectors trong các bài viết tiếp theo.


Bài tập thực hành

  1. Tạo một Stream từ một danh sách các chuỗi và lọc ra các chuỗi có độ dài lớn hơn 5. In kết quả ra màn hình.

  2. Sử dụng Stream để tính tổng bình phương của các số nguyên từ một danh sách.

  3. Tạo một Stream từ một mảng số nguyên và sắp xếp chúng theo thứ tự tăng dần. In kết quả ra màn hình.


Gợi ý đáp án

  1. Lọc chuỗi có độ dài lớn hơn 5:

     List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
     names.stream()
          .filter(name -> name.length() > 5)
          .forEach(System.out::println); // Charlie
    
  2. Tính tổng bình phương:

     List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
     int sumOfSquares = numbers.stream()
                               .map(n -> n * n)
                               .reduce(0, Integer::sum);
     System.out.println(sumOfSquares); // 55
    
  3. Sắp xếp mảng số nguyên:

     int[] numbers = {5, 3, 1, 4, 2};
     Arrays.stream(numbers)
           .sorted()
           .forEach(System.out::println); // 1, 2, 3, 4, 5
    

Kết luận

Bài viết này đã giới thiệu chi tiết về Stream trong Java 8, từ khái niệm cơ bản đến cách tạo và sử dụng các thao tác trên Stream. Hiểu rõ Stream là nền tảng để áp dụng các tính năng nâng cao như Parallel StreamCollectors trong các bài viết tiếp theo.

More from this blog

hoangkim

366 posts