Come peek () e allMatch () lavorano insieme nell'API Stream di Java 8


10

Ho trovato un quiz sull'API Java 8 Stream del metodo peek come di seguito

Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));

L'output è

Fred
Jim

Sono confuso su come funziona questo stream? Il mio risultato atteso dovrebbe essere

Fred
Jim
Sheila

Il metodo peek () è un'operazione intermedia ed elabora ogni elemento in Stream. Qualcuno può spiegarmi questo.

Risposte:


10

È un'ottimizzazione del flusso nota come corto circuito. In sostanza, ciò che accade è che allMatchimpedisce l'esecuzione di operazioni intermedie non necessarie sullo stream, poiché non ha senso eseguirle quando è noto il risultato finale.

È come se fosse successo:

take"Fred"
peek("Fred")
evaluate("Fred".startsWith("F"))
decide whether the result of allMatch() is known for sure: Not yet

take"Jim"
peek("Jim")
evaluate("Jim".startsWith("F"))
decide whether the result of allMatch() is known for sure: Yes

Quando "Jim".startsWith("F")viene valutato, il risultato di allMatch(s -> s.startsWith("F"))è noto per certo. Non importa quali valori arrivano dopo "Jim", sappiamo che tutti i valori che iniziano con "F" sono falsi

Questo non è specifico della combinazione peek/ allMatch, ci sono più operazioni di corto circuito intermedio e terminale. stato dei java.util.streamdocumenti del pacchetto :

Inoltre, alcune operazioni sono considerate operazioni di corto circuito. Un'operazione intermedia è in corto circuito se, se presentato con input infinito, può produrre un flusso finito di conseguenza. Un'operazione terminale è in corto circuito se, quando presentata con input infinito, può terminare a 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 tempo finito.

Estendilo a flussi limitati e le operazioni di corto circuito impediscono l'esecuzione di passaggi della pipeline non necessari, come nel caso del tuo esempio.


5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • Prima volta, Fredviene stampato. Si abbina così
  • La seconda volta, Jimviene stampato. Non corrisponde, quindi allMatch termina perché "Tutto non corrisponde"
  • Quindi l'ultimo elemento non è stato consumato dallo stream.

3

I documenti per il peekmetodo dicono (enfasi mia):

Restituisce un flusso costituito dagli elementi di questo flusso, eseguendo inoltre l'azione fornita su ciascun elemento quando gli elementi vengono consumati dal flusso risultante .

Quindi, in questo caso, peeknon si vede "Sheila"perché quel valore non viene consumato dallo stream. Non appena è "Jim"stato consumato, il risultato di .allMatch(s -> s.startsWith("F"))è già noto per essere false, quindi non è necessario consumare più elementi dal flusso.


1

Secondo Java Doc Of allMatch ():

Indica se tutti gli elementi di questo flusso corrispondono al predicato fornito. Potrebbe non valutare il predicato su tutti gli elementi se non necessario per determinare il risultato. Se il flusso è vuoto, viene restituito {@code true} e il predicato non viene valutato.

@apiNote

Questo metodo valuta la quantificazione universale del predicato sugli elementi del flusso (per tutti x P (x)). Se il flusso è vuoto, si dice che la quantificazione è soddisfatta vagamente ed è sempre {@code true} (indipendentemente da P (x)).

predicato da applicare agli elementi di questo flusso @return {@code true} se tutti gli elementi del flusso corrispondono al predicato fornito o il flusso è vuoto, altrimenti {@code false}

Nel tuo caso:

1-

p(x) : s -> s.startsWith("F")

X : "Fred"

result : X P(X) = true

2-

p(x) : s -> s.startsWith("F")

X : "Jim"

result : X P(X) = false

Non verrà effettuata alcuna ulteriore valutazione, poiché XP (X) = false

boolean result = Arrays.asList("Fred", "Finda", "Fish")
            .stream()
            .peek(System.out::println)
            .allMatch(s -> s.startsWith("F"));
    System.out.println("Result "+result);

L'output è:

Fred
Finda
Fish
Result true

Qui lo stream è stato elaborato completamente perché xP (x) = true da ciascun elemento

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.