2015-12-09 12 views
32
List<Integer> integer = Stream.generate(new Supplier<Integer>() { 
    int i = 0 ; 

    @Override 
    public Integer get() { 
     return ++i; 
    } 
}).filter(j -> j < 5) 
    .limit(10) // Note the call to limit here 
    .collect(Collectors.toList()); 

Contrariamente alle mie aspettative, la chiamata collect non restituisce mai. L'impostazione limit prima dello filter produce il risultato previsto. Perché?Perché Stream.limit non funziona come previsto in questo snippet?

+4

A proposito, è possibile utilizzare 'Stream.iterate (1, i -> i + 1) .filter (...) ...' invece di questo fornitore funky. –

+0

@AlexisC. Non ero a conoscenza di questa API. Grazie! – Vitaliy

+2

O meglio, IntStream.range(). –

risposta

31

Poiché ci sono solo 4 elementi che passano il filtro, limit(10) non raggiunge mai 10 elementi, quindi la pipeline Stream continua a generare nuovi elementi e li alimenta al filtro, cercando di raggiungere 10 elementi che passano il filtro, ma poiché solo il i primi 4 elementi passano il filtro, l'elaborazione non finisce mai (almeno fino a i overflow).

La pipeline Stream non è abbastanza intelligente da sapere che nessun altro elemento può passare il filtro, quindi continua a elaborare nuovi elementi.

+0

Ma certo! :-) roba da subire .. – Vitaliy

+0

"La pipeline' Stream' non è abbastanza intelligente per sapere che non ci sono più elementi in grado di passare il filtro "... e, infatti, [non può essere] (https: //en.wikipedia. org/wiki/Halting_problem). – wchargin

25

La rotazione delle clausole limit e filter presenta comportamenti diversi.

Se si mette il primo limit, il flusso sarà innanzitutto generare 10 numeri interi [1..10], e poi filtrare lasciando loro solo quelli più piccoli 5.

Nel ordinamento originale, con il filter applicare per primo , gli interi vengono generati e filtrati fino a raggiungere 10 elementi. Questo non è un operatore infinito, poiché il i nel fornitore finirà per traboccare, ma ci vorrà un po ', specialmente su un computer lento, per raggiungere MAX_INT.

+4

Non ho considerato l'eventuale overflow int. +1 – Eran

+1

Forse si tratta di quando l'ottimizzatore inizia a funzionare, ma sulla mia macchina, l'overflow e il successivo completamento dell'operazione avvengono in meno di un secondo ... – Holger

16

Se si desidera interrompere sia se il numero 5 è stato raggiunto o 10 elementi sono raccolti, c'è Stream.takeWhile() metodo aggiunto in Java-9:

List<Integer> integer = Stream.generate(new Supplier<Integer>() { 
    int i = 0 ; 

    @Override 
    public Integer get() { 
     return ++i; 
    } 
}).takeWhile(j -> j < 5).limit(10).collect(Collectors.toList()); 
9

finirà, dopo gli overflow del fornitore e inizia a generare numeri negativi La lista risultante conterrà:

[1, 2, 3, 4, -2147483648, -2147483647, -2147483646, -2147483645, -2147483644, -2147483643] 

La ragione di questo è in altre risposte. Sulla mia macchina i7 ci sono voluti 40 secondi per completare.

Problemi correlati