2015-08-24 18 views
10

Leggendo un po 'su Java 8, ho ottenuto il post del blog this spiegando un po' di flussi e riduzione di essi e quando sarebbe stato possibile cortocircuitare la riduzione. In basso si legge:Java 8 stream in cortocircuito

Nota nel caso di findFirst o findAny abbiamo solo bisogno il primo valore che corrisponde al predicato (anche se findAny non è garantito per restituire la prima). Tuttavia, se lo stream non ha ordini, ci aspetteremmo che findFirst si comporti come findAny. Le operazioni allMatch, noneMatch e anyMatch non possono cortocircuitare il flusso poiché potrebbe richiedere la valutazione di tutti i valori per determinare se l'operatore è true o false. Quindi un flusso infinito che utilizza questi non può terminare.

ottengo che findFirst o findAny può cortocircuitare la riduzione, perché non appena AF a trovare un elemento, non hai bisogno di elaborare ulteriormente qualsiasi.

Ma perché questo non sarebbe possibile per allMatch, noneMatch e anyMatch? Per allMatch, se ne trovi uno che non corrisponde al predicato, puoi interrompere l'elaborazione. Lo stesso per nessuno. E anyMatch in particolare non ha senso per me, in quanto è praticamente uguale a findAny (ad eccezione di ciò che viene restituito)?

Dire che questi tre non possono cortocircuitare, perché potrebbe richiedere la valutazione di tutti i valori, si potrebbe anche dire per findFirst/Any.

C'è qualche differenza fondamentale che mi manca? Non capisco davvero cosa sta succedendo?

+0

"non può" come in "potrebbe non", non come in "non consentito". – Andreas

+0

@Andreas Sì, non sto ottenendo da dove viene la differenza. Tutto può essere cortocircuitato nel modo in cui lo sto guardando? – Koekje

risposta

12

C'è una sottile differenza, perché la famiglia anyMatch utilizza un predicato, mentre la famiglia findAny non lo fa. Tecnicamente lo findAny() si presenta come anyMatch(x -> true) e anyMatch(pred) come filter(pred).findAny(). Quindi qui abbiamo un altro problema. Considerare abbiamo un semplice flusso infinito:

Stream<Integer> s = Stream.generate(() -> 1); 

Allora è vero che l'applicazione findAny() a tale flusso sarà sempre il corto circuito e la finitura durante l'applicazione anyMatch(pred) dipende dal predicato. Tuttavia filtriamo il nostro flusso infinito:

Stream<Integer> s = Stream.generate(() -> 1).filter(x -> x < 0); 

Il flusso risultante è infinito? Questa è una domanda complicata. In realtà non contiene elementi, ma per determinarlo (ad esempio, usando .iterator().hasNext()) dobbiamo controllare il numero infinito di elementi di flusso sottostanti, quindi questa operazione non finirà mai. Chiamerei anche questo flusso infinito. Tuttavia utilizzando tale flusso sia anyMatch e findAny non potrà mai finire:

Stream.generate(() -> 1).filter(x -> x < 0).anyMatch(x -> true); 
Stream.generate(() -> 1).filter(x -> x < 0).findAny(); 

Quindi findAny() non è garantito per finire o, dipende da precedenti operazioni di flusso intermedio.

Per concludere, ritengo che il post di blog sia molto fuorviante. A mio parere, il comportamento del flusso infinito è meglio spiegato in JavaDoc ufficiale.

+0

Grazie per la spiegazione! :) – Koekje

1

Quando javadoc dice "potrebbe non cortocircuitare", si limita a sottolineare che non si tratta di un'operazione di cortocircuito e, a seconda dei valori, è possibile elaborare l'intero flusso.

findFirst e findAny d'altra parte, sono garantiti a corto circuito poiché non hanno mai bisogno di elaborare il resto del flusso una volta che sono soddisfatti.

+0

Ma potrebbe anche succedere per i predicati, non appena sono (soddisfatti)? – Koekje

0

anyMatch, noneMatch e allMatch restituiscono valori booleani, quindi potrebbero dover controllare tutti per provare la logica.

findFirst e find A tutti interessa trovare il primo possibile e restituirlo.

Modifica: Per un determinato set di dati è garantito che i metodi di corrispondenza restituiscono sempre lo stesso valore, tuttavia i metodi di ricerca non sono perché l'ordine può variare e influire sul valore restituito.

Il cortocircuito descritto sta parlando dei metodi Find privi di coerenza per un determinato set di dati.

+0

Ma anyMatch fa altrettanto? – Koekje

+0

Se l'ultimo valore era la corrispondenza, allora sì. Il punto è che i metodi di corrispondenza restituiranno sempre lo stesso valore sullo stesso set di dati, ma i metodi di ricerca non sono garantiti dalla coerenza poiché l'ordine potrebbe essere diverso. –

+0

Questa mancanza di coerenza è il cortocircuito descritto –

5

risposta Aggiornato

direi che il post sul blog è sbagliato quando si dice "FindFirst o findAny abbiamo solo bisogno il primo valore che corrisponde al predicato".

Nel javadoc per allMatch(Predicate), anyMatch(Predicate), noneMatch(Predicate), findAny() e findFirst():

Questa è un'operazione terminale cortocircuito.

Si noti tuttavia che findFirst e findAny non hai Predicate. Quindi possono entrambi tornare immediatamente dopo aver visto il primo/qualsiasi valore. Gli altri 3 sono condizionali e possono essere interrotti per sempre se la condizione non si attiva mai.

+0

Dal blog: "Le operazioni allMatch, noneMatch e anyMatch non possono cortocircuitare il flusso poiché potrebbe richiedere la valutazione di tutti i valori per determinare se l'operatore è vero o falso. " Questo è ovviamente errato poiché 'allMatch' può essere determinato come falso non appena viene trovata la prima non corrispondenza. –

+0

@MiserableVariable Come ho detto, il post sul blog è sbagliato. Loro * possono * tutti i cortocircuiti. --- Il blog ha ragione che 3 di loro potrebbero * potenzialmente * funzionare per sempre, ma dice tutto sbagliato. – Andreas

1

Da Documentation Stream Oracle: https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#StreamOps

Un'operazione terminale è corto circuito se, quando sono presentati con ingresso infinita, può terminare in tempo finito. Avere un'operazione di cortocircuito nella pipeline è una condizione necessaria, ma non sufficiente, per l'elaborazione di un flusso infinito per terminare normalmente in un tempo finito.

Tutti e cinque funzioni hanno la linea:

Questa è un'operazione terminale cortocircuito.

Nella descrizione della funzione.

+0

Grazie per il riferimento del documento! – Koekje