J'ai le code suivant:
Stream<String> lines = reader.lines();
Si la première chaîne est égale à, "email"
je veux supprimer la première chaîne du flux. Pour les autres chaînes du flux, je n'ai pas besoin de cette vérification.
Comment pourrais-je y parvenir?
PS
Bien sûr, je peux le transformer en liste, puis utiliser la vieille école pour la boucle, mais j'ai encore besoin de diffuser à nouveau.
java
java-stream
java-11
gstackoverflow
la source
la source
skip(long n)
ça qui saute les premiersn
éléments, mais je ne sais pas si vous pouvez le conditionner d'une manière ou d'une autre ...stream.dropWhile(s -> s.equals("email"));
Réponses:
Bien que le lecteur soit dans un état non spécifié après que vous en ayez construit un flux de lignes, il est dans un état bien défini avant de le faire.
Vous pouvez donc faire
Quelle est la solution la plus propre à mon avis. Notez que ce n'est pas la même chose que Java 9
dropWhile
, qui laisserait tomber plus d'une ligne si elles correspondent.la source
Si vous ne pouvez pas avoir la liste et devez le faire avec seulement un
Stream
, vous pouvez le faire avec une variable.Le fait est que vous ne pouvez utiliser une variable que si elle est "finale" ou "effectivement finale", vous ne pouvez donc pas utiliser un booléen littéral. Vous pouvez toujours le faire avec
AtomicBoolean
:Remarque: Je n'aime pas utiliser des "variables externes" dans un
Stream
car les effets secondaires sont une mauvaise pratique dans le paradigme de programmation fonctionnelle. De meilleures options sont les bienvenues.la source
compareAndSet
est une façon très élégante de régler et d'obtenir le drapeau en même temps, c'est bien.stream.filter(!first.compareAndSet(true, false) || !s.equals("email"))
être discutable.predicate
doit être apatrideAtomicBoolean
ici est de prendre en charge des flux parallèles (comme lecompareAndSet
suggère l'utilisation de ), cela est complètement faux car cela ne fonctionnera que si le flux est séquentiel.stream.sequential().filter(...)
Cependant, si vous utilisez la technique, je suis d'accord qu'elle fonctionnera.Pour éviter de vérifier la condition sur chaque ligne du fichier, je voudrais simplement lire et vérifier la première ligne séparément, puis exécuter le pipeline sur le reste des lignes sans vérifier la condition:
Plus simple sur Java 9+:
la source
Stream.ofNullable(first).filter(not("email"::equals))
La réponse @Arnouds est correcte. Vous pouvez créer un flux pour la première ligne, puis comparer comme ci-dessous,
la source
limit(0)
devrait sûrement êtrelimit(1)
….limit(0).filter(line -> !line.startsWith("email"))
cela n'a aucun sens. Le prédicat ne sera jamais évalué. Pour une source de flux capable de reproduire des flux, la combinaison dulimit(1)
premier etskip(1)
du second serait correcte. Pour une source de flux comme un lecteur,limit(1)
nilimit(0)
ne fonctionnera. Vous venez de changer la ligne qui est avalée sans condition. Même si vous trouviez une combinaison qui fait la chose souhaitée, ce serait sur la base d'un comportement non spécifié, dépendant de l'implémentation.Pour filtrer les éléments en fonction de leur index, vous pouvez utiliser
AtomicInteger
pour stocker et incrémenter l'index lors du traitement d'unStream
:Cette approche permet de filtrer les éléments à n'importe quel index, pas seulement le premier.
la source
Un peu plus compliqué, s'inspirant de cet extrait .
Vous pouvez créer un
Stream<Integer>
qui représentera les index et le "zip" avec votreStream<String>
pour créer unStream<Pair<String, Integer>>
Filtrez ensuite à l'aide de l'index et mappez-le sur un
Stream<String>
la source
Voici un exemple avec
Collectors.reducing
. Mais à la fin crée une liste de toute façon.la source
Essaye ça:
la source