Conditionnellement ajouter une opération de Java 8 flux
Je me demande si je peux ajouter une opération à un flux de données, basé sur une sorte de condition fixée à l'extérieur du cours d'eau. Par exemple, je veux ajouter une limite de fonctionnement de la transmission si mon limit
variable n'est pas égale à -1
.
Mon code ressemble à ça, mais je n'ai pas encore voir d'autres exemples de flux utilisé de cette façon, lorsqu'un objet de Flux de données est réaffecté à la suite d'un intermédiaire en opération appliquée à lui-même:
//Do some stream stuff
stream = stream.filter(e -> e.getTimestamp() < max);
//Limit the stream
if (limit != -1) {
stream = stream.limit(limit);
}
//Collect stream to list
stream.collect(Collectors.toList());
Comme indiqué dans ce stackoverflow post, le filtre n'est pas appliqué jusqu'à ce qu'un terminal opération est appelée. Depuis que je suis à la réaffectation de la valeur de flux avant d'un terminal de fonctionnement est appelé, est le code ci-dessus encore une bonne façon d'utiliser Java 8 flux?
- Il semble que vous n'êtes pas capturer la sortie de
stream.filter()
. - Si vous voulez l'écrire en une seule ligne, vous pouvez écrire
.limit(limit != -1 ? limit : Long.MAX_VALUE)
mais je ne le ferais pas. - Mon erreur, j'ai oublié d'affecter la valeur de la filtrés flux de
stream
dans mon premier exemple de code. Je suppose que j'ai compris les flux de manière incorrecte. J'ai lu que tous les cours d'eau devait être suivie par une exploitation du terminal pour être exécuté, alors j'ai pensé qu'il était incorrect de stocker le flux dans le mêmestream
variable. Je vais mettre à jour ma question d'origine. - Noter qu'il y a une fonctionnalité intéressante proposition dans OpenJDK: ajout de
chain()
méthode. Avoir votre problème sera résolu dans une seule expression commestream.filter(...).chain(s -> limit == -1 ? s : s.limit(limit)).collect(toList())
. Actuellement, le statut de cette fonction n'est pas claire: il n'est même pas marqué pour être ajouté dans JDK-9.
Vous devez vous connecter pour publier un commentaire.
Il n'y a pas de différence sémantique entre un enchaînés série d'invocations et d'une série d'invocations de stocker l'intermédiaire des valeurs de retour. Ainsi, le code suivant fragments sont équivalentes:
et
Dans les deux cas, chaque méthode est appelée sur le résultat de l'invocation précédente. Mais dans ce dernier cas, les résultats intermédiaires ne sont pas stockées mais a perdu sur la prochaine invocation. Dans le cas du flux de l'API, les résultats intermédiaires ne doit pas être utilisé après avoir appelé la méthode suivante, donc le chaînage est le moyen le plus naturel à l'aide de flux comme intrinsèquement vous permet de ne pas invoquer plus d'une méthode sur un retourné de référence.
Encore, il n'est pas mauvais pour stocker la référence à un flux de données tant que vous respectez le contrat de ne pas utiliser un retourné de référence plus d'une fois. En l'utilisant, ils manière que dans votre question, à savoir l'écrasement de la variable avec le résultat de l'appel suivant, vous pouvez également vous assurer de ne pas invoquer plus d'une méthode sur un retourné de référence, donc, c'est une utilisation correcte. Bien sûr, cela ne fonctionne qu'avec les résultats intermédiaires du même type, de sorte que lorsque vous utilisez
map
ouflatMap
, l'obtention d'un flux de données d'un autre type de référence, vous ne pouvez pas remplacer la variable locale. Ensuite, vous devez être prudent de ne pas utiliser l'ancienne variable locale à nouveau, mais, comme l'a dit, aussi longtemps que vous ne l'utilisez pas après la prochaine invocation, il n'y a rien de mal avec le stockage intermédiaire.Parfois, vous ont pour stocker, par exemple
Notez que le code est équivalent pour les alternatives suivantes:
et
Ils sont équivalents, car
forEach
est toujours invoquée sur le résultat defilter
qui est toujours appelée sur le résultat deFiles.lines
et il n'a pas d'importance sur le résultat de qui le finalclose()
opération est invoquée comme la fermeture affecte l'ensemble du flux de l'oléoduc.De le mettre dans une phrase, à la façon dont vous l'utilisez, est correcte.
J'ai même préfèrent de le faire de cette façon, ne pas enchaînant un
limit
opération, lorsque vous ne voulez pas appliquer une limite est la façon la plus propre de l'expression de votre intention. Il est également intéressant de noter que les solutions de rechange proposées peuvent travailler dans beaucoup de cas, mais ils sont pas sémantiquement équivalentes:suppose que le nombre maximal d'éléments, vous pouvez toujours rencontre, est
Long.MAX_VALUE
mais des cours d'eau peut avoir plus d'éléments que ça, ils ont même peut-être infini.lorsque le flux de la source est
list
, est la rupture de l'évaluation différée d'un ruisseau. En principe, une mutable stream source peut légalement obtenir arbitrairement modifiées jusqu'au moment où le terminal de l'action est engagée. Le résultat sera de refléter toutes les modifications effectuées jusqu'à ce point. Lorsque vous ajoutez un intermédiaire en opération intégrantlist.size()
, c'est à dire la taille réelle de la liste à ce stade, les modifications appliquées à la collecte entre ce point et l'exploitation du terminal peut transformer cette valeur pour avoir un sens différent que les “en réalité aucune limite sémantique”.Comparer avec “Non Ingérence” de la section de la documentation de l'API:
De sûr, c'est un rare cas de coin que normalement, un programmeur de formuler un ensemble de flux d'un pipeline, sans modifier le code source de la collecte entre les deux. Encore, les différentes sémantiques reste et il peut devenir très difficile de trouver un bug lorsque vous une fois entrée dans un tel cas de coin.
Plus loin, puisqu'elles ne sont pas équivalentes, le flux de l'API ne sera jamais reconnaître ces valeurs comme “en réalité aucune limite”. Même en précisant
Long.MAX_VALUE
implique que le flux de la mise en œuvre doit suivre le nombre de traités éléments pour s'assurer que la limite a été obéi. Donc, ne pas ajouter unlimit
opération peut avoir un avantage de performance significative sur l'ajout d'une limite avec un nombre que le programmeur s'attend à ne jamais être dépassée.Je pense que votre première ligne doit être:
de sorte que votre utiliser le flux de données retourné par le filtre dans la suite des opérations plutôt que le flux d'origine.
Il y a deux façons dont vous pouvez faire cette
OU
Que c'est fonctionnelle de programmation, vous devez toujours travailler sur le résultat de chaque fonction. Vous devriez éviter d'avoir à modifier quoi que ce soit dans ce style de programmation et de traiter de tout comme si c'était immuable, si possible.
Il devrait fonctionner, cependant, il se lit comme un mélange de impératif et fonctionnel de codage. Je suggère la rédaction d'un fixe de flux comme par ma première réponse.
.limit(limit > 0 ? limit : Long.MAX_VALUE)
dans le cas où le flux n'est pas basé sur une collection.