web-dev-qa-db-fra.com

Quelles opérations préservent l'ordre

TL; DR; Je cherche un endroit où je peux rechercher une opération intermédiaire ou terminale. Où puis-je trouver une telle documentation?

Edit Ceci n'est pas une copie de Comment assurer l'ordre de traitement dans les flux Java8? , puisque cette question ne fournit pas une liste complète des opérations.

Contexte

Le la documentation du paquet dit:

Qu'un flux ait ou non un ordre de rapprochement dépend de la source et des opérations intermédiaires

Ce qui est répété dans cette excellente réponse stackoverflow

Afin de garantir la maintenance de la commande tout au long d’une opération de flux, vous devez étudier la documentation de la source du flux, toutes les opérations intermédiaires et l’opération du terminal afin de déterminer si elles maintiennent ou non la commande (ou si la source a une commande dans la première endroit).

C'est très bien, mais quelle documentation dois-je consulter? Le la documentation du paquet indique dans un exemple que map garantit la commande, mais il n'a pas de liste exhaustive. Le javadoc de la classe Stream documente certaines opérations intermédiaires, mais pas toutes les ..___. Prenez par exemple map :

Renvoie un flux contenant les résultats de l'application de la fonction donnée aux éléments de ce flux.

C'est une opération intermédiaire.

ou filter

Retourne un flux composé des éléments de ce flux qui correspondent au prédicat donné.

C'est une opération intermédiaire.

Aucune de celles-ci ne décrit si elles préservent l'ordre.

Cette réponse de stackoverflow déclare:

En réalité, chaque opération intermédiaire conserve un ordre par défaut. Les seules exceptions sont:

  • unordered () qui supprime la contrainte de classement.
  • trié () qui change l'ordre.

Lorsque ce n'est pas explicitement spécifié, vous pouvez supposer que l'opération conserve l'ordre. Même distinct () conserve l'ordre, même s'il ajoute beaucoup de complexité au flux parallèle.

mais y a-t-il une documentation officielle pour sauvegarder cela?

Crédit supplémentaire ????

Il a en fait deux problèmes de commande distincts.

  1. La sortie de l'opération conserve-t-elle le même ordre que l'entrée?
  2. L'opération est-elle exécutée dans l'ordre sur chaque élément?.

Par exemple, une opération parallèle map peut parcourir tous les éléments dans un ordre arbitraire (en violation de 2.), tout en maintenant l'ordre dans le flux renvoyé (en obéissant à 1.).

16
Tobber

Après quelques recherches dans le code source, j'ai résumé les tableaux suivants:

Extrait de: Java streams - Part 6 - Spliterator

Le tableau suivant montre quels types d'opérations sont autorisés à modifier des caractères:

|                        | DISTICTS | SORTED | ORDERED | SIZED | SHORT_CIRCUIT |
| ---------------------- | -------- | ------ | ------- | ----- | --------------|
| source stream          | Y        | Y      | Y       | Y     | N             |
| intermediate operation | PCI      | PCI    | PCI     | PC    | PI            |
| terminal operation     | N        | N      | PC      | N     | PI            |
  • Y - Autorisé à avoir
  • P - Conserves de mai
  • C - May efface. 
  • I - Mai injecte. 
  • N - Non valide. Non pertinent pour l'opération.

Extrait de flux Java - Tableau de caractéristiques des méthodes de flux

Le tableau suivant indique les caractéristiques et les indicateurs que chaque opération intermédiaire/opération de terminal peut activer et désactiver: (SHORT_CIRCUIT est pertinent uniquement dans le contexte des indicateurs StreamOpFlag)

Remarque: Un indicateur P (Conserver) est ajouté à chaque cellule, à l'exception de celles comportant les indicateurs C et I (Effacer et injecter).

|                  |  DISTINCT |  SORTED |  ORDERED |  SIZED |  SHORT_CIRCUIT |
| ---------------- | ----------| --------| ---------| -------| ---------------|
|  filter          |           |         |          |  C     |                |
|  forEach         |           |         |  C       |        |                |
|  forEachOrdered  |           |         |          |        |                |
|  allMatch        |           |         |  C       |        |  I             |
|  distinct        |  I        |         |          |  C     |                |
|  flatMap         |  C        |  C      |          |  C     |                |
|  anyMatch        |           |         |  C       |        |  I             |
|  collect         |           |         |          |        |                |
|  unOrdered       |           |         |  C       |        |                |
|  count           |  C        |  C      |  C       |  C     |                |
|  findAny         |           |         |  C       |        |  I             |
|  findFirst       |           |         |          |        |  I             |
|  flatMapToXXX    |  C        |  C      |          |  C     |                |
|  limit           |           |         |          |  C     |  I             |
|  map             |  C        |  C      |          |        |                |
|  mapToXXX        |  C        |  C      |          |        |                |
|  max             |           |         |          |        |                |
|  min             |           |         |          |        |                |
|  noneMatch       |           |         |  C       |        |  I             |
|  peek            |           |         |          |        |                |
|  reduce          |           |         |          |        |                |
|  skip            |           |         |  C       |  I     |                |
|  sorted          |           |  I      |  I       |        |                |
|  toArray         |           |         |          |        |                |
  • C - Efface. 
  • I - Injects. 
17
Stav Alfi

Cela ressemble en quelque sorte à deux doublons, car les deux réponses que vous avez liées expliquent les choses. Je ne peux pas dire si map ou filter devrait spécifiquement indiquer qu'ils préservent l'ordre; ils ne s'appuient sur aucun état précédent ni sur aucun autre état (il s'agit d'opérations sans état). Il est donc implicite qu'ils préservent l'ordre aussi loin que je peux voir. Je vois les choses autrement, s’ils ne conservent pas l’ordre - cela devrait être explicitement mentionné dans la documentation; si ce n'est pas évident à partir du nom de l'opération . Par exemple, Stream.generate ne m'apparaît pas évident s'il génère un flux ordonné; c'est ce qui est dit dans la documentation:

Renvoie un flux séquentiel infini non ordonné dans lequel chaque élément est généré par le fournisseur fourni. 

sorted et unordered sont en revanche assez évidents (IMO) pour changer de commande, du moins lorsque vous les mettez - vous dites explicitement que vous ne vous souciez pas de la commande. unordered btw ne fera pas de randomisation à dessein pour y arriver, vous pouvez en lire plus ici .

Il y a en général deux ordres: ordre de traitement et ordre de rencontre.

Vous pouvez penser à order order comme un traitement de gauche à droite (imaginez que vous avez une List ou une array). Donc, si vous avez un pipeline qui ne change pas d'ordre, les éléments seront envoyés à la Collector (ou à toute autre opération de terminal) comme vu de gauche à droite. Eh bien pas toutes les opérations de terminal sont comme ça. Une différence évidente est forEach et forEachOrdered; ou un Collectors.toSet - qui n'a pas besoin de préserver la commande initiale du tout. Ou prenons findAny comme opération terminale - de toute évidence, vous ne vous souciez pas de l'élément que vous voulez, alors pourquoi se donner la peine d'alimenter findAny dans un ordre exact au départ?

L'ordre de traitement, en revanche, n'a pas d'ordre défini - particulièrement visible pour le traitement en parallèle évidemment. Ainsi, même si votre pipeline est parallèle (et que les éléments sont traités sans aucune garantie de l'ordre), ils continueront à être alimentés dans le fonctionnement du terminal dans l'ordre - si un tel ordre est nécessaire pour cette opération du terminal. 

1
Eugene