Comment peek () et allMatch () fonctionnent ensemble dans l'API Java 8 Stream

10

J'ai trouvé un quiz sur l'API Java 8 Stream de la méthode peek comme ci-dessous

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

La sortie est

Fred
Jim

Je ne sais pas comment ce flux fonctionne? Mon résultat attendu devrait être

Fred
Jim
Sheila

La méthode peek () est une opération intermédiaire et elle traite chaque élément dans Stream. Quelqu'un peut-il m'expliquer cela.

Barcelone
la source

Réponses:

10

C'est une optimisation de flux connue sous le nom de court-circuit. Essentiellement, ce qui se passe est d' allMatchempêcher l'exécution d' opérations intermédiaires inutiles sur le flux, car il est inutile de les exécuter lorsque le résultat final est connu.

C'est comme si cela s'était produit:

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

Quand "Jim".startsWith("F")est évalué, le résultat de allMatch(s -> s.startsWith("F"))est connu avec certitude. Peu importe les valeurs à venir dans le pipeline "Jim", nous savons que toutes les valeurs commençant par "F" sont fausses

Ceci n'est pas spécifique à la combinaison peek/ allMatch, il existe de multiples opérations de court-circuitage intermédiaire et terminal. java.util.streamles documents du package indiquent:

De plus, certaines opérations sont considérées comme des opérations de court-circuit. Une opération intermédiaire court-circuite si, lorsqu'elle est présentée avec une entrée infinie, elle peut produire un flux fini en conséquence. Une opération de terminal court-circuite si, lorsqu'elle est présentée avec une entrée infinie, elle peut se terminer en temps fini. La présence d'une opération de court-circuit dans le pipeline est une condition nécessaire, mais non suffisante, pour que le traitement d'un flux infini se termine normalement en un temps fini.

Étendez cela aux flux finis et les opérations de court-circuit évitent l'exécution d'étapes de pipeline inutiles, comme dans le cas de votre exemple.

ernest_k
la source
5
Arrays.asList("Fred", "Jim", "Sheila")
      .stream()
      .peek(System.out::println)
      .allMatch(s -> s.startsWith("F"));
  • Première fois, Fredest imprimé. Il correspond donc
  • La deuxième fois, Jimest imprimée. Il ne correspond pas, donc allMatch se termine car "Tout ne correspond pas"
  • Le dernier élément n'a donc pas été consommé dans le flux.
WJS
la source
3

Les documents de la peekméthode disent (soulignement le mien):

Renvoie un flux composé des éléments de ce flux, effectuant en outre l'action fournie sur chaque élément lorsque les éléments sont consommés à partir du flux résultant .

Donc, dans ce cas, peekne voit pas "Sheila"parce que cette valeur n'est pas consommée par le flux. Dès qu'il a "Jim"été consommé, le résultat de .allMatch(s -> s.startsWith("F"))est déjà connu false, il n'est donc pas nécessaire de consommer plus d'éléments du flux.

kaya3
la source
1

Selon Java Doc Of allMatch ():

Renvoie si tous les éléments de ce flux correspondent au prédicat fourni. Peut ne pas évaluer le prédicat sur tous les éléments s'il n'est pas nécessaire pour déterminer le résultat. Si le flux est vide, {@code true} est renvoyé et le prédicat n'est pas évalué.

@apiNote

Cette méthode évalue la quantification universelle du prédicat sur les éléments du flux (pour tous x P (x)). Si le flux est vide, la quantification est dite satisfaite de manière vide et est toujours {@code true} (quel que soit P (x)).

prédicat à appliquer aux éléments de ce flux @return {@code true} si tous les éléments du flux correspondent au prédicat fourni ou si le flux est vide, sinon {@code false}

Dans ton cas:

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

Aucune autre évaluation n'aura lieu, car 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);

La sortie est:

Fred
Finda
Fish
Result true

Ici le flux est complètement traité car xP (x) = true à partir de chaque élément

Sandeep Tiwari
la source