Skip to main content

Command Palette

Search for a command to run...

Bài 7: Sử dụng Predicate và Function trong Stream

Published
5 min readView as Markdown

Mục tiêu:

  • Hướng dẫn chi tiết cách sử dụng PredicateFunction trong Stream API của Java 8.

  • Giải thích cách kết hợp PredicateFunction để lọc và biến đổi dữ liệu trong 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. Predicate trong Stream

Predicate<T> là một Functional Interface được sử dụng để kiểm tra một điều kiện trên đối tượng kiểu T. Nó thường được sử dụng trong các thao tác lọc dữ liệu (filtering) trong Stream.

  1. Cú pháp cơ bản:

    • Phương thức test(T t) của Predicate trả về giá trị boolean.

    • Ví dụ:

        Predicate<Integer> isEven = num -> num % 2 == 0;
        System.out.println(isEven.test(4)); // true
      
  2. Sử dụng Predicate trong Stream:

    • Phương thức filter(Predicate<T>) trong Stream dùng để lọc các phần tử thỏa mãn điều kiện.

    • Ví dụ: Lọc các số chẵn từ một danh sách:

        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> evenNumbers = numbers.stream()
                                           .filter(n -> n % 2 == 0) // Sử dụng Predicate
                                           .collect(Collectors.toList());
        System.out.println(evenNumbers); // [2, 4, 6]
      
  3. Kết hợp nhiều Predicate:

    • Sử dụng các phương thức and(), or(), và negate() để kết hợp nhiều điều kiện.

    • Ví dụ: Lọc các số chẵn và lớn hơn 3:

        Predicate<Integer> isEven = num -> num % 2 == 0;
        Predicate<Integer> isGreaterThan3 = num -> num > 3;
        List<Integer> result = numbers.stream()
                                      .filter(isEven.and(isGreaterThan3))
                                      .collect(Collectors.toList());
        System.out.println(result); // [4, 6]
      

2. Function trong Stream

Function<T, R> là một Functional Interface được sử dụng để biến đổi dữ liệu từ kiểu T sang kiểu R. Nó thường được sử dụng trong các thao tác biến đổi dữ liệu (mapping) trong Stream.

  1. Cú pháp cơ bản:

    • Phương thức apply(T t) của Function trả về giá trị kiểu R.

    • Ví dụ:

        Function<String, Integer> stringLength = str -> str.length();
        System.out.println(stringLength.apply("Java")); // 4
      
  2. Sử dụng Function trong Stream:

    • Phương thức map(Function<T, R>) trong Stream dùng để biến đổi từng phần tử.

    • Ví dụ: Chuyển đổi các chuỗi thành chữ in hoa:

        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        List<String> upperCaseNames = names.stream()
                                           .map(String::toUpperCase) // Sử dụng Function
                                           .collect(Collectors.toList());
        System.out.println(upperCaseNames); // [ALICE, BOB, CHARLIE]
      
  3. Kết hợp nhiều Function:

    • Sử dụng phương thức andThen() hoặc compose() để kết hợp nhiều Function.

    • Ví dụ: Chuyển đổi chuỗi thành chữ in hoa và sau đó lấy độ dài:

        Function<String, String> toUpperCase = String::toUpperCase;
        Function<String, Integer> getLength = String::length;
        Function<String, Integer> transform = toUpperCase.andThen(getLength);
      
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        List<Integer> lengths = names.stream()
                                     .map(transform)
                                     .collect(Collectors.toList());
        System.out.println(lengths); // [5, 3, 7]
      

3. Kết hợp Predicate và Function trong Stream

PredicateFunction có thể được kết hợp để thực hiện các thao tác phức tạp hơn, chẳng hạn như lọc dữ liệu trước khi biến đổi.

  1. Ví dụ: Lọc và biến đổi dữ liệu:

    • Lọc các số chẵn và sau đó tính bình phương của chúng:

        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        List<Integer> result = numbers.stream()
                                      .filter(n -> n % 2 == 0) // Lọc số chẵn
                                      .map(n -> n * n)        // Tính bình phương
                                      .collect(Collectors.toList());
        System.out.println(result); // [4, 16, 36]
      
  2. Ví dụ: Lọc và chuyển đổi chuỗi:

    • Lọc các chuỗi có độ dài lớn hơn 3 và chuyển đổi thành chữ in hoa:

        List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
        List<String> result = names.stream()
                                   .filter(name -> name.length() > 3) // Lọc chuỗi
                                   .map(String::toUpperCase)         // Chuyển đổi
                                   .collect(Collectors.toList());
        System.out.println(result); // [ALICE, CHARLIE, DAVID]
      

Ví dụ tổng hợp

  1. Sử dụng PredicateFunction trong Stream:

     List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
     List<String> result = names.stream()
                                .filter(name -> name.length() > 3) // Lọc chuỗi
                                .map(String::toUpperCase)         // Chuyển đổi
                                .collect(Collectors.toList());
     System.out.println(result); // [ALICE, CHARLIE, DAVID]
    
  2. Kết hợp nhiều PredicateFunction:

     List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
     Predicate<Integer> isEven = num -> num % 2 == 0;
     Predicate<Integer> isGreaterThan3 = num -> num > 3;
     Function<Integer, Integer> square = num -> num * num;
    
     List<Integer> result = numbers.stream()
                                   .filter(isEven.and(isGreaterThan3)) // Lọc số chẵn và > 3
                                   .map(square)                       // Tính bình phương
                                   .collect(Collectors.toList());
     System.out.println(result); // [16, 36]
    

Tổng kết

  • Predicate<T> được sử dụng để lọc dữ liệu trong Stream thông qua phương thức filter().

  • Function<T, R> được sử dụng để biến đổi dữ liệu trong Stream thông qua phương thức map().

  • Kết hợp PredicateFunction giúp thực hiện các thao tác phức tạp như lọc và biến đổi dữ liệu một cách hiệu quả.


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

  1. Tạo một Stream từ một danh sách các số nguyên và lọc ra các số lớn hơn 10. Sau đó, tính bình phương của các số này và in kết quả ra màn hình.

  2. 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. Sau đó, chuyển đổi các chuỗi này thành chữ thường và in kết quả ra màn hình.

  3. Kết hợp nhiều Predicate để lọc các số nguyên dương và chia hết cho 3. Sau đó, tính tổng các số này.


Gợi ý đáp án

  1. Lọc và tính bình phương:

     List<Integer> numbers = Arrays.asList(5, 12, 8, 15, 3);
     List<Integer> result = numbers.stream()
                                   .filter(n -> n > 10) // Lọc số > 10
                                   .map(n -> n * n)    // Tính bình phương
                                   .collect(Collectors.toList());
     System.out.println(result); // [144, 225]
    
  2. Lọc và chuyển đổi chuỗi:

     List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
     List<String> result = names.stream()
                                .filter(name -> name.length() > 5) // Lọc chuỗi > 5 ký tự
                                .map(String::toLowerCase)         // Chuyển đổi thành chữ thường
                                .collect(Collectors.toList());
     System.out.println(result); // [charlie]
    
  3. Kết hợp nhiều Predicate và tính tổng:

     List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 9, 12);
     Predicate<Integer> isPositive = num -> num > 0;
     Predicate<Integer> isDivisibleBy3 = num -> num % 3 == 0;
    
     int sum = numbers.stream()
                      .filter(isPositive.and(isDivisibleBy3)) // Lọc số dương và chia hết cho 3
                      .mapToInt(Integer::intValue)           // Chuyển đổi thành IntStream
                      .sum();                                // Tính tổng
     System.out.println(sum); // 30
    

Kết luận

Bài viết này đã hướng dẫn chi tiết cách sử dụng PredicateFunction trong Stream API của Java 8. Hiểu rõ cách kết hợp các Functional Interface này giúp bạn xử lý dữ liệu một cách hiệu quả và linh hoạt trong các bài toán thực tế.

More from this blog

hoangkim

366 posts