2014-09-18 11 views
6

Nella mia applicazione Spring, ho un repository Couchbase per un tipo di documento di QuoteOfTheDay. Il documento è molto semplice, ha solo un campo id di tipo UUID, campo valore di tipo String e campo data di creazione di tipo Data.Java 8 Stream.findAny() rispetto alla ricerca di un elemento casuale nello stream

Nella mia classe di servizio, ho un metodo che restituisce una citazione casuale del giorno. Inizialmente ho provato semplicemente a fare quanto segue, che ha restituito un argomento di tipo Optional<QuoteOfTheDay>, ma sembrerebbe che findAny() restituisca quasi sempre lo stesso elemento nel flusso. Ci sono solo circa 10 elementi al momento.

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

Poiché volevo qualcosa di più casuale, ho realizzato le seguenti che restituisce solo un 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."); 
    } 
} 

Sono solo curioso come il metodo di flusso findAny() effettivamente funziona in quanto non sembra essere casuale.

Grazie.

risposta

21

Il motivo alla base di findAny() è di fornire un'alternativa più flessibile a findFirst(). Se non sei interessato a ottenere un elemento specifico, questo fornisce al flusso di implementazione una maggiore flessibilità nel caso si tratti di un flusso parallelo.

Non verrà effettuato alcuno sforzo per rendere casuale l'elemento restituito, semplicemente non offre le stesse garanzie di findFirst() e potrebbe pertanto essere più veloce.

Questo è ciò che la Javadoc dice sull'argomento:

Il comportamento di questa operazione è esplicitamente non deterministico; è libero di selezionare qualsiasi elemento nello stream. Questo per consentire la massima prestazione nelle operazioni parallele; il costo è che più invocazioni sulla stessa fonte potrebbero non restituire lo stesso risultato. (Se un risultato stabile è desiderato, utilizzare FindFirst(), invece.)

10

Non raccogliere in un List quando invece si è un singolo elemento. Basta scegliere un oggetto dal flusso. Selezionando l'articolo tramite le operazioni Stream, è possibile gestire anche i conteggi più grandi di Integer.MAX_VALUE e non è necessario il modo "interessante" di nascondere il fatto che si sta eseguendo una ricerca lunga su un(la cosa 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(); 
} 
Problemi correlati