Written By : Nguyễn Văn Linh
Gmail : Linhthai130100@gmail.com

1.Giới thiệu

Trong hướng dẫn nhanh 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.

Link bài viết tham khảo :Java Stream Filter with Lambda Expression

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

Phương thức filter () là một hoạt động trung gian của giao diện Luồng cho phép chúng tôi lọc các phần tử của luồng phù hợp với một vị trí nhất định :

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 Khách hàng :

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:

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 Lọc bộ sưu tập

Một trường hợp sử dụng phổ biến của phương thức filter () là 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 tôi đã thêm phương thức hasOverHundredPoints vào lớp Khách hàng của chúng tôi :

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

Trong cả hai trường hợp, chúng tôi nhận được cùng một kết quả:

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

2.2 Lọc bộ sưu tập với nhiều tiêu chí

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ý các trường hợp ngoại lệ

Cho đến nay, chúng tôi vẫn đang sử dụng bộ lọc với các vị từ 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 một gói tùy chỉnh

Trước tiên, chúng tôi sẽ bắt đầu bằng cách thêm một profilePhotoUrl cho Khách hàng của chúng tôi :

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 tôi 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 tôi 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 vị từ 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 tôi 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 phụ thuộc hàm ném vào pom của chúng tôi:

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

Để xử lý các ngoại lệ trong các vị từ, 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ó trong hành động:

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 tôi 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ệ.