2014-09-18 20 views
6

Trong ứng dụng Spring của tôi, tôi có kho lưu trữ Couchbase cho loại tài liệu là QuoteOfTheDay. Tài liệu này rất cơ bản, chỉ có một trường id kiểu UUID, trường giá trị kiểu String và trường ngày tạo kiểu Date.Java 8 Stream.findAny() vs tìm một phần tử ngẫu nhiên trong luồng

Trong lớp dịch vụ của tôi, tôi có phương thức trả về một trích dẫn ngẫu nhiên trong ngày. Ban đầu tôi đã cố gắng làm như sau, trả về một đối số kiểu Optional<QuoteOfTheDay>, nhưng có vẻ như findAny() khá nhiều sẽ luôn trả về cùng một phần tử trong luồng. Hiện tại chỉ có khoảng 10 yếu tố.

public Optional<QuoteOfTheDay> random() { 
    return StreamSupport.stream(repository.findAll().spliterator(), false).findAny(); 
} 

Vì tôi muốn một điều gì đó ngẫu nhiên hơn, tôi đã triển khai thực hiện các bước sau chỉ trả về QuoteOfTheDay.

public QuoteOfTheDay random() { 
    int count = Long.valueOf(repository.count()).intValue(); 

    if(count > 0) { 
     Random r = new Random(); 

     List<QuoteOfTheDay> quotes = StreamSupport.stream(repository.findAll().spliterator(), false) 
       .collect(toList()); 

     return quotes.get(r.nextInt(count)); 
    } else { 
     throw new IllegalStateException("No quotes found."); 
    } 
} 

Tôi chỉ tò mò như thế nào phương pháp findAny() của Suối thực sự hoạt động vì nó dường như không phải là ngẫu nhiên.

Cảm ơn.

Trả lời

21

Lý do đằng sau findAny() là cung cấp giải pháp linh hoạt hơn cho findFirst(). Nếu bạn không quan tâm đến việc nhận được một phần tử cụ thể, điều này cho phép luồng triển khai linh hoạt hơn trong trường hợp đó là luồng song song.

Không có nỗ lực nào được thực hiện để ngẫu nhiên phần tử được trả về, nó không đảm bảo cùng một mức độ như findFirst() và do đó có thể nhanh hơn.

Đây là những gì Javadoc nói về đề tài này:

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

10

Không thu thập vào một List khi tất cả các bạn muốn là một mục duy nhất. Chỉ cần chọn một mục từ luồng. Bằng cách chọn mục qua các hoạt động Stream, bạn thậm chí có thể xử lý số lượng lớn hơn Integer.MAX_VALUE và không cần cách "thú vị" để che giấu thực tế rằng bạn đang truyền một số dài đến một số int (điều đó Long.valueOf(repository.count()).intValue()).

public Optional<QuoteOfTheDay> random() { 
    long count = repository.count(); 
    if(count==0) return Optional.empty(); 
    Random r = new Random(); 
    long randomIndex=count<=Integer.MAX_VALUE? r.nextInt((int)count): 
     r.longs(1, 0, count).findFirst().orElseThrow(AssertionError::new); 
    return StreamSupport.stream(repository.findAll().spliterator(), false) 
     .skip(randomIndex).findFirst(); 
} 
Các vấn đề liên quan