1.Giới thiệu

Trong hướng dẫn này, chúng ta sẽ khám phá cách sử dụng phương thức Stream.filter () khi chúng ta làm việc với Stream trong Java .

Chúng ta sẽ xem xét cách sử dụng nó và cách xử lý các trường hợp đặc biệt với các ngoại lệ đã chọn.

2.Sử dụng Stream.filter()

Phương thức filter () là một thao tác trung gian của giao diện luồng cho phép chúng ta lọc các phần tử của luồng phù hợp với một Predicate:

Stream<T> filter(Predicate<? super T> predicate)

Để xem cách này hoạt động như thế nào, hãy tạo một lớp Customer :

public class Customer {
    private String name;
    private int points;
    //Constructor and standard getters
}

Ngoài ra, hãy tạo một tập hợp khách hàng (customers):

Customer john = new Customer("John P.", 15);
Customer sarah = new Customer("Sarah M.", 200);
Customer charles = new Customer("Charles B.", 150);
Customer mary = new Customer("Mary T.", 1);

List<Customer> customers = Arrays.asList(john, sarah, charles, mary);

2.1. Filtering Collections

Một trường hợp sử dụng phổ biến của phương thức filter ()xử lý các tập hợp.

Hãy lập danh sách những khách hàng có hơn 100 điểm. Để làm điều đó, chúng ta có thể sử dụng biểu thức lambda:

List<Customer> customersWithMoreThan100Points = customers
  .stream()
  .filter(c -> c.getPoints() > 100)
  .collect(Collectors.toList());

Chúng ta cũng có thể sử dụng tham chiếu phương thức, viết tắt của biểu thức lambda:

List<Customer> customersWithMoreThan100Points = customers
  .stream()
  .filter(Customer::hasOverHundredPoints)
  .collect(Collectors.toList());

Trong trường hợp này, chúng ta đã thêm phương thức hasOverHHundredPoints vào lớp Customer:

public boolean hasOverHundredPoints() {
    return this.points > 100;
}

Trong cả hai trường hợp này , chúng ta sẽ nhận được cùng một kết quả:

assertThat(customersWithMoreThan100Points).hasSize(2);
assertThat(customersWithMoreThan100Points).contains(sarah, charles);

2.2. Filtering Collections với Multiple Criteria

Hơn nữa, chúng ta có thể sử dụng nhiều điều kiện với filter ().
Ví dụ: chúng tôi có thể lọc theo điểm và tên:

List<Customer> charlesWithMoreThan100Points = customers
  .stream()
  .filter(c -> c.getPoints() > 100 && c.getName().startsWith("Charles"))
  .collect(Collectors.toList());

assertThat(charlesWithMoreThan100Points).hasSize(1);
assertThat(charlesWithMoreThan100Points).contains(charles);

3.Xử lý ngoại lệ

Cho đến nay, chúng ta vẫn đang sử dụng bộ lọc với các thuộc tính không có ngoại lệ. Thật vậy, các giao diện chức năng trong Java không khai báo bất kỳ ngoại lệ nào được kiểm tra hoặc không được kiểm tra.

Tiếp theo, chúng tôi sẽ chỉ ra một số cách khác nhau để xử lý các ngoại lệ trong biểu thức lambda.

3.1.Sử dụng lớp bao bọc (wrapper) tuỳ chỉnh

Trước tiên, chúng ta sẽ bắt đầu bằng cách thêm một profilePhotoUrl cho Customer :

private String profilePhotoUrl;

Ngoài ra, hãy thêm một phương thức hasValidProfilePhoto () đơn giản để kiểm tra tính khả dụng của hồ sơ:

public boolean hasValidProfilePhoto() throws IOException {
    URL url = new URL(this.profilePhotoUrl);
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
}

Chúng ta có thể thấy rằng phương thức hasValidProfilePhoto () ném một IOException. Bây giờ nếu chúng ta cố gắng lọc khách hàng bằng phương pháp này:

List<Customer> customersWithValidProfilePhoto = customers
  .stream()
  .filter(Customer::hasValidProfilePhoto)
  .collect(Collectors.toList());

Chúng ta sẽ thấy lỗi sau:

Incompatible thrown types java.io.IOException in functional expression

Để xử lý nó, một trong những lựa chọn thay thế mà chúng ta có thể sử dụng là bọc nó bằng một khối try-catch:

List<Customer> customersWithValidProfilePhoto = customers
  .stream()
  .filter(c -> {
      try {
          return c.hasValidProfilePhoto();
      } catch (IOException e) {
          //handle exception
      }
      return false;
  })
  .collect(Collectors.toList());

Nếu chúng ta cần ném một ngoại lệ khỏi predicate của mình, chúng ta có thể bọc nó trong một ngoại lệ không được kiểm tra như RuntimeException.

3.2. Sử dụng ThrowingFunction

Ngoài ra, chúng ta có thể sử dụng thư viện ThrowingFunction.

ThrowingFunction là một thư viện mã nguồn mở cho phép chúng ta xử lý các ngoại lệ đã được kiểm tra trong các giao diện chức năng Java.

Hãy bắt đầu bằng cách thêm throwing-function dependency vào file pom:

<dependency>
    <groupId>pl.touk</groupId>
    <artifactId>throwing-function</artifactId>
    <version>1.3</version>
</dependency>

Để xử lý các ngoại lệ trong các predicates, thư viện này cung cấp cho chúng ta lớp ThrowingPredicate, lớp này có phương thức unchecked () để bọc các ngoại lệ đã được kiểm tra.

Hãy xem nó qua hành động sau:

List customersWithValidProfilePhoto = customers
  .stream()
  .filter(ThrowingPredicate.unchecked(Customer::hasValidProfilePhoto))
  .collect(Collectors.toList());

4.Kết luận

Trong bài viết này, chúng ta đã thấy một ví dụ về cách sử dụng phương thức filter ()
để xử lý các luồng. Chúng ta cũng đã khám phá một số lựa chọn thay thế để xử lý các trường hợp ngoại lệ.

Như mọi khi, mã hoàn chỉnh có sẵn trên GitHub.


Tham khảo tại: https://www.baeldung.com/java-stream-filter-lambda