Sự khác biệt giữa findAny () và findFirst () trong Java 8


90

Tôi ít nhầm lẫn giữa Stream#findAny()Stream#findFirst()các StreamAPI trong Java 8.

Điều tôi hiểu là cả hai sẽ trả về phần tử phù hợp đầu tiên từ luồng, chẳng hạn khi được sử dụng cùng với bộ lọc?

Vì vậy, tại sao hai phương pháp cho cùng một nhiệm vụ? Tui bỏ lỡ điều gì vậy?

Câu trả lời:


92

Điều tôi hiểu là cả hai sẽ trả về phần tử phù hợp đầu tiên từ luồng, chẳng hạn khi được sử dụng cùng với bộ lọc?

Đo không phải sự thật. Theo javadoc, Stream#findAny():

Trả về Optional<T>mô tả một số phần tử của luồng hoặc giá trị trống Optional<T>nếu luồng trống. Hành vi của hoạt động này rõ ràng là không xác định; có thể tự do chọn bất kỳ phần tử nào trong luồng. Điều này cho phép đạt được hiệu suất tối đa trong các hoạt động song song;

trong khi Stream.findFirst()sẽ trả về một Optional<T>mô tả đúng các yếu tố đầu tiên của dòng. Các Streamlớp không có một .findOne()phương pháp, vì vậy tôi giả sử bạn có nghĩa là .findFirst().


Tôi vẫn chưa hiểu, vì vậy những gì bạn đang nói là ngay cả sau khi filteráp dụng a, findAnycó thể trả về bất kỳ phần tử nào, bao gồm cả phần tử không khớp với bộ lọc được áp dụng?
Koray Tugay

@KorayTugay - Không, sau khi bộ lọc, bất kỳ phần tử còn lại nào hiện diện, findAnyđều có thể trả về bất kỳ phần tử nào từ đó theo (loại) ngẫu nhiên, đặc biệt là trong các hoạt động dòng song song
KrishPrabakar

46

Không, cả hai sẽ không trả về phần tử đầu tiên của Luồng.

Từ Stream.findAny()(nhấn mạnh của tôi):

Trả về Optionalmô tả một số phần tử của luồng hoặc giá trị trống Optionalnếu luồng trống.

Đây là một hoạt động đầu cuối ngắn mạch.

Hành vi của hoạt động này rõ ràng là không xác định; có thể tự do chọn bất kỳ phần tử nào trong luồng . Điều này cho phép đạt được hiệu suất tối đa trong các hoạt động song song; chi phí là nhiều lệnh gọi trên cùng một nguồn có thể không trả lại cùng một kết quả. (Nếu mong muốn kết quả ổn định, hãy sử dụng findFirst()thay thế.)

Vì vậy, nói một cách đơn giản hơn, nó có thể chọn hoặc không chọn phần tử đầu tiên của Stream.

Với cách triển khai cụ thể của Oracle hiện tại, tôi tin rằng nó sẽ trả về phần tử đầu tiên trong đường ống không song song. Tuy nhiên, trong một đường ống song song, nó sẽ không luôn luôn (thực thi ví dụ System.out.println(IntStream.range(0, 100).parallel().findAny());, nó trả về OptionalInt[50]khi tôi chạy nó). Nhưng dù sao, bạn không được dựa vào đó.


16

findFirst trả về các phần tử đầu tiên của luồng nhưng findAny có quyền chọn bất kỳ phần tử nào trong luồng.

List<String> lst1 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");
List<String> lst2 = Arrays.asList("Jhonny", "David", "Jack", "Duke", "Jill","Dany","Julia","Jenish","Divya");

Optional<String> findFirst = lst1.parallelStream().filter(s -> s.startsWith("D")).findFirst();
Optional<String> fidnAny = lst2.parallelStream().filter(s -> s.startsWith("J")).findAny();

System.out.println(findFirst.get()); //Always print David
System.out.println(fidnAny.get()); //Print Jack/Jill/Julia :behavior of this operation is explicitly nondeterministic

1

trong chế độ song song findAny, thứ tự không được đảm bảo, nhưng findFirstcó.

Tôi đã viết một số đoạn mã để thể hiện sự khác biệt, hãy truy cập nó


1

Trong luồng findFirst và findAny trả về phần tử đầu tiên và không thực thi phần còn lại nhưng trong song songStream, không thể thông qua thứ tự và song songStream thực thi phần còn lại của tập hợp.

Tài liệu tham khảo

Thời gian 1:25:00


1

Tôi sẽ chỉ nói rằng hãy cẩn thận findFirst()findAny()trong khi sử dụng.

Từ Javadoc của họ ( ở đâyở đây ), cả hai phương thức đều trả về một phần tử tùy ý từ luồng - trừ khi luồng có thứ tự gặp phải , trong trường hợp này findFirst()trả về phần tử đầu tiên while findAny()sẽ trả về bất kỳ phần tử nào.

Giả sử chúng ta có listISBN và tên SÁCH tùy chỉnh . Để có kịch bản, hãy xem ví dụ này:

public class Solution {
   private Integer ISBN;
   private String BookName;

public Solution(int i, String string) {
    ISBN =i;
    BookName = string;
}
//getters and setters
}

public static void main(String[] args) {
        List<Solution> Library = Arrays.asList(new Solution(12,"Java in Action"),new Solution(13,"Java 8"),new Solution(15,"Java 8 Features"),new Solution(16,"Java in Action"));
 System.out.println(Library.stream()
        .map(p->p.getBookName())
        .sorted(Comparator.reverseOrder())
        .findFirst());
    }

Đầu ra :Optional[Java in Action]

Có thể có trường hợp khi Tên sách giống nhau nhưng số ISBN khác nhau, trong trường hợp đó, việc phân loại và tìm sách có thể giống nhau nhiều findAny()và sẽ cho kết quả sai. Hãy nghĩ đến tình huống có 5 cuốn sách được đặt tên là "Tài liệu tham khảo Java" nhưng có số ISBN khác nhau và findFirst()cuốn sách theo tên sẽ dẫn đến kết quả giống như findAny().

Hãy nghĩ về một tình huống trong đó:

 ISBN    Name Of book
+-----+------------------+
| 100 | Java-8 in Action |
+-----+------------------+
| 101 | Java-8 in Action |
+-----+------------------+
| 102 | Java-8 in Action |
+-----+------------------+
| 103 | Java-8 in Action |
+-----+------------------+
| 104 | Java-8 in Action |
+-----+------------------+

ở đây findFirst () và findAny () sẽ cho cùng một kết quả ngay cả khi được sắp xếp trên BookByName.

Bài viết chi tiết:


-1

Khi nào Streamlà không có thứ tự, findFirst()findAny()giống nhau. Nhưng khi Streamđược đặt hàng, findAny()sẽ tốt hơn.


Điều này là không chính xác. Cả hai phương pháp này đều không "tốt hơn", bởi vì các hành vi và trường hợp sử dụng của chúng hoàn toàn khác nhau. Ngoài ra, bạn có nghĩa là gì Streamkhi được "đặt hàng"? Nó luôn được sắp xếp theo thứ tự (các hoạt động được thực hiện theo Streamcùng một thứ tự mọi lúc khi nó không song song), nhưng có lẽ không được người dùng sắp xếp.
Jezor
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.