Đừng đánh đồng findFirst() và findAny() trong Stream API

Java 8 Stream API cung cấp 2 method thường xuyên được sử dụng: findAny()findFirst(), tuy nhiên mọi người thường xem chúng như nhau và sử dụng tuỳ ý chứ không theo một chủ đích nào. Trong bài viết này, chúng ta sẽ đi tìm sự khác biệt và cách sử dụng đúng 2 method này.

Cách sử dụng Stream.findAny()

Giống như cái tên, findAny() cho phép chúng ta lấy một giá trị bất kỳ từ Stream mà không quan tâm đến thứ tự các phần tử trong nó. findAny() trả về Optional instance, nếu Stream rỗng thì findAny() trả về Empty Optional.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

class test {
    public static void main(String[] agrs) {
        List<Integer> integers = Arrays.asList(-5, 5, 23, 4, 0, -1, 3);

        Optional<Integer> value = integers.stream()
                .filter(i -> i >= 0 && i <= 5)
                .findAny();

        value.ifPresent(v -> System.out.println(v));

    }
}

Output: 5

Khi findAny() hoạt động trên non-parallel Stream, thông thường nó sẽ trả về phần tử đầu tiên của Stream vì findAny() sẽ chọn phần tử dựa trên tập kết quả đã hoàn tất các hoạt động trung gian, tuy nhiên cũng có thể xuất hiện kết quả khác không ai đảm bảo cho chúng ta điều đó.

Trên parallel Stream findAny() sẽ cho hiệu xuất tối đa khi mà kết quả sẽ không được xác định trước vì các hoạt động trung gian thực thi song song, khi có kết quả thoả điều kiện ngay lập tức nó sẽ được trả về.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

class test {
    public static void main(String[] agrs) {
        List<Integer> integers = Arrays.asList(-5, 5, 23, 4, 0, -1, 3);

        Optional<Integer> value = integers.stream().parallel()
                .filter(i -> i >= 0 && i <= 5)
                .findAny();

        value.ifPresent(v -> System.out.println(v));

    }
}

Output: kết quả là tập hợp các số {5, 4, 0, 3} thay đổi ở mỗi lần chạy

Thông thường sử dụng findAny() nếu chúng ta cần một thông tin mà tất cả các phần tử trong Stream đều hoàn toàn giống nhau.

Cách sử dụng findFirst()

Sử dụng findFirst() khi muốn tìm phần tử đầu tiên trong Stream. Tuy nhiên Stream có thể không định nghĩa thứ tự các phần tử, điều này phụ thuộc vào nguồn tài nguyên và các hoạt động trung gian. Khi không được định nghĩa thứ tự, findFirst() cũng sẽ trả về phần tử bất kỳ trong Stream.

findFirst() cũng trả về một Optional instance.

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

class test {
    public static void main(String[] agrs) {
        List<Integer> integers = Arrays.asList(-5, 5, 23, 4, 0, -1, 3);

        Optional<Integer> value = integers.stream()
                .sorted()
                .findFirst();

        value.ifPresent(v -> System.out.println(v));

    }
}

Output: -5

Note: findFirst() hoạt động như nhau trên non-parallel và parallel Stream.

Chúng ta thường sử dụng findFirst() khi chắc rằng sau khi Stream trải qua các hoạt động trung gian thì chỉ còn duy nhất một phần tử hoặc đã qua hoạt động sắp xếp.

Tóm lược

Như vậy chúng ta đã biết được các điểm khác biệt giữa findFirst()findAny() method, và hãy sử dụng đúng cách để có thể tăng một ít hiệu xuất cho chương trình của bạn. 

Tài liệu tham khảo

https://www.baeldung.com/java-stream-findfirst-vs-findany

Leave a Comment

Your email address will not be published. Required fields are marked *