Je peux ajouter des flux ou des éléments supplémentaires, comme ceci:
Stream stream = Stream.concat(stream1, Stream.concat(stream2, Stream.of(element));
Et je peux ajouter de nouvelles choses au fur et à mesure, comme ceci:
Stream stream = Stream.concat(
Stream.concat(
stream1.filter(x -> x!=0), stream2)
.filter(x -> x!=1),
Stream.of(element))
.filter(x -> x!=2);
Mais c'est moche, car concat
c'est statique. Siconcat
s'agissait d'une méthode d'instance, les exemples ci-dessus seraient beaucoup plus faciles à lire:
Stream stream = stream1.concat(stream2).concat(element);
Et
Stream stream = stream1
.filter(x -> x!=0)
.concat(stream2)
.filter(x -> x!=1)
.concat(element)
.filter(x -> x!=2);
Ma question est:
1) Y a-t-il une bonne raison pour laquelle concat
est statique? Ou y a-t-il une méthode d'instance équivalente qui me manque?
2) Dans tous les cas, y a-t-il une meilleure façon de procéder?
java
concat
java-8
java-stream
MarcG
la source
la source
Réponses:
Si vous ajoutez des importations statiques pour Stream.concat et Stream.of , le premier exemple peut être écrit comme suit:
L'importation de méthodes statiques avec des noms génériques peut entraîner un code qui devient difficile à lire et à maintenir ( pollution de l'espace de noms ). Il serait donc préférable de créer vos propres méthodes statiques avec des noms plus significatifs. Cependant, pour la démonstration, je m'en tiendrai à ce nom.
Avec ces deux méthodes statiques (éventuellement en combinaison avec des importations statiques), les deux exemples pourraient être écrits comme suit:
Le code est désormais nettement plus court. Cependant, je reconnais que la lisibilité ne s'est pas améliorée. J'ai donc une autre solution.
Dans de nombreuses situations, les collecteurs peuvent être utilisés pour étendre les fonctionnalités des flux. Avec les deux collecteurs en bas, les deux exemples pourraient être écrits comme suit:
La seule différence entre la syntaxe souhaitée et la syntaxe ci-dessus est que vous devez remplacer concat (...) par collect (concat (...)) . Les deux méthodes statiques peuvent être implémentées comme suit (éventuellement utilisées en combinaison avec des importations statiques):
Bien entendu, cette solution présente un inconvénient qu'il convient de mentionner. collect est une opération finale qui consomme tous les éléments du flux. En plus de cela, le collecteur concat crée une ArrayList intermédiaire à chaque fois qu'il est utilisé dans la chaîne. Les deux opérations peuvent avoir un impact significatif sur le comportement de votre programme. Cependant, si la lisibilité est plus importante que les performances , cela peut toujours être une approche très utile.
la source
concat
collectionneur très lisible. Il semble étrange d'avoir une méthode statique à paramètre unique nommée comme ceci, et également de l'utilisercollect
pour la concaténation.It's a bad idea to import static methods with names
? Je suis vraiment intéressé - je trouve que cela rend le code plus concis et plus lisible et beaucoup de gens à qui j'avais demandé pensaient la même chose. Voulez-vous donner quelques exemples pourquoi c'est généralement mauvais?compare(reverse(getType(42)), of(6 * 9).hashCode())
? Notez que je n'ai pas dit que les importations statiques sont une mauvaise idée, mais que les importations statiques pour des noms génériques commeof
etconcat
sont.Malheureusement, cette réponse n'aide probablement que peu ou pas du tout, mais j'ai fait une analyse médico-légale de la liste de diffusion Java Lambda pour voir si je pouvais trouver la cause de cette conception. C'est ce que j'ai découvert.
Au début, il y avait une méthode d'instance pour Stream.concat (Stream)
Dans la liste de diffusion, je peux clairement voir que la méthode a été implémentée à l'origine comme méthode d'instance, comme vous pouvez le lire dans ce fil de discussion de Paul Sandoz, à propos de l'opération concat.
Dans ce document, ils discutent des problèmes qui pourraient résulter des cas dans lesquels le flux pourrait être infini et de ce que la concaténation signifierait dans ces cas, mais je ne pense pas que ce soit la raison de la modification.
Vous voyez dans cet autre fil de discussion que certains premiers utilisateurs du JDK 8 se sont interrogés sur le comportement de la méthode d'instance concat lorsqu'elle est utilisée avec des arguments nuls.
Cet autre fil révèle cependant que la conception de la méthode concat était en discussion.
Refactorisé en Streams.concat (Stream, Stream)
Mais sans aucune explication, tout à coup, les méthodes ont été changées en méthodes statiques, comme vous pouvez le voir dans ce fil sur la combinaison de flux . C'est peut-être le seul fil de discussion qui jette un peu de lumière sur ce changement, mais ce n'était pas assez clair pour que je puisse déterminer la raison du refactoring. Mais nous pouvons voir qu'ils ont fait un commit dans lequel ils ont suggéré de déplacer la
concat
méthode horsStream
et dans la classe d'assistanceStreams
.Refactorisé en Stream.concat (Stream, Stream)
Plus tard, il a été déplacé à nouveau de
Streams
àStream
, mais encore une fois, aucune explication à cela.Donc, en fin de compte, la raison de la conception n'est pas tout à fait claire pour moi et je n'ai pas pu trouver une bonne explication. Je suppose que vous pouvez toujours poser la question dans la liste de diffusion.
Quelques alternatives pour la concaténation de flux
Cet autre fil de discussion de Michael Hixson discute / pose des questions sur d'autres façons de combiner / concaténer des flux
la source
public static <T> Stream<T> concat(Stream<T>... streams) { return Stream.of(streams).reduce(Stream.empty(), Stream::concat);}
@SafeVarargs private static <T> Stream<T> concat(Stream<? extends T>... streams) { return Stream.of(streams).reduce(Stream.empty(),Stream::concat).map(Function.identity());}
Function.identity()
carte? Après tout, il renvoie le même argument qu'il reçoit. Cela ne devrait avoir aucun effet sur le flux résultant. Est-ce que je manque quelque chose?return Stream.of(streams).reduce(Stream.empty(),Stream::concat)
renvoie Stream <? étend T>. (Quelque chose <T> est le sous-type de Quelque chose <? étend T>, pas l'inverse, donc il ne peut pas être casté) Cast supplémentaire.map(identity())
<? étend T> à <T>. Cela se produit grâce au mélange de java 8 'types de cible' d'arguments de méthode et de types de retour et de signature de la méthode map (). En fait, c'est Function. <T> identity ().? extends T
, car vous pouvez utiliser la conversion de capture . En tout cas, voici mon extrait de code général Continuons la discussion dans le Gist.Ma bibliothèque StreamEx étend les fonctionnalités de l'API Stream. En particulier, il propose des méthodes telles que l' ajout et le préfixe qui résolvent ce problème (ils utilisent en interne
concat
). Ces méthodes peuvent accepter un autre flux ou une autre collection ou un tableau de varargs. En utilisant ma bibliothèque, votre problème peut être résolu de cette façon (notez que celax != 0
semble étrange pour un flux non primitif):Au fait, il existe également un raccourci pour votre
filter
opération:la source
Faites simplement:
où
identity()
est une importation statique deFunction.identity()
.Concaténer plusieurs flux en un seul flux équivaut à aplatir un flux.
Cependant, malheureusement, pour une raison quelconque, il n'y a pas de
flatten()
méthode activéeStream
, vous devez donc l'utiliserflatMap()
avec la fonction d'identité.la source
Vous pouvez utiliser la méthode de Guava , qui sera très courte avec les importations statiques:
Streams
.
concat(Stream<? extends T>... streams)
la source
Si cela ne vous dérange pas d'utiliser des bibliothèques tierces, cyclops-react a un type de flux étendu qui vous permettra de le faire via les opérateurs d'ajout / d'avance.
Des valeurs individuelles, des tableaux, des itérables, des flux ou des flux réactifs Les éditeurs peuvent être ajoutés et ajoutés en tant que méthodes d'instance.
[Divulgation Je suis le principal développeur de cyclops-react]
la source
En fin de compte, je ne suis pas intéressé par la combinaison de flux, mais par l'obtention du résultat combiné du traitement de chaque élément de tous ces flux.
Bien que la combinaison de flux puisse s'avérer fastidieuse (donc ce thread), la combinaison de leurs résultats de traitement est assez facile.
La clé à résoudre est de créer votre propre collecteur et de vous assurer que la fonction fournisseur du nouveau collecteur renvoie la même collection à chaque fois ( pas une nouvelle ), le code ci-dessous illustre cette approche.
la source
Que diriez-vous d'écrire votre propre méthode concat?
Cela rend au moins votre premier exemple beaucoup plus lisible.
la source