2014-09-18 10 views
6

W mojej aplikacji Spring mam repozytorium Couchbase dla typu dokumentu QuoteOfTheDay. Dokument jest bardzo prosty, ma tylko pole id typu UUID, pole wartości typu String i utworzone pole daty typu Date.Java 8 Stream.findAny() vs znajdowanie losowego elementu w strumieniu

W mojej klasie usług, mam metodę, która zwraca losową ofertę dnia. Początkowo próbowałem po prostu wykonać następujące czynności, które zwróciły argument typu Optional<QuoteOfTheDay>, ale wydaje się, że findAny() prawie zawsze zwraca ten sam element w strumieniu. W tej chwili jest tylko około 10 elementów.

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

Ponieważ chciałem coś bardziej losowy, I wdrożone następujące która po prostu zwraca 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."); 
    } 
} 

Jestem tylko ciekaw, jak metoda Stream findAny() faktycznie działa, ponieważ nie wydaje się być przypadkowe.

Dzięki.

Odpowiedz

21

Powodem jest zapewnienie bardziej elastycznej alternatywy dla findFirst(). Jeśli nie jesteś zainteresowany uzyskaniem określonego elementu, daje to strumień implementacji większą elastyczność w przypadku, gdy jest to strumień równoległy.

Nie zostanie podjęta żadna próba randomizacji zwróconego elementu, po prostu nie daje takich samych gwarancji, co findFirst(), a zatem może być szybsza.

To właśnie Javadoc mówi na ten temat:

Zachowanie tej operacji jest wyraźnie niedeterministyczny; można wybrać dowolny element w strumieniu. Ma to na celu zapewnienie maksymalnej wydajności w równoległych operacjach; koszt jest taki, że wiele wywołań z tego samego źródła może nie zwrócić tego samego wyniku. (Jeśli pożądany jest stabilny wynik, użyj FindFirst() zamiast.)

10

Nie zbierają się w List gdy chcesz to pojedynczy egzemplarz. Po prostu wybierz jeden przedmiot ze strumienia. Wybierając przedmiot za pomocą operacji Stream, można nawet obsłużyć liczby większe niż Integer.MAX_VALUE i nie trzeba "interesującego" sposobu ukrywania faktu, że rzucasz długo na rzecz o nazwie int (ta rzecz: int (to: int).

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(); 
} 
Powiązane problemy