Comment faire pour convertir un itérateur d'un ruisseau?
Je suis à la recherche d'une manière concise pour convertir un Iterator
à un Stream
ou plus précisément de "voir" l'itérateur comme un flux.
Pour des raisons de performances, je voudrais éviter une copie de l'itérateur dans une nouvelle liste:
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Collection<String> copyList = new ArrayList<String>();
sourceIterator.forEachRemaining(copyList::add);
Stream<String> targetStream = copyList.stream();
Basé sur les quelques suggestions dans les commentaires, j'ai aussi essayé d'utiliser Stream.générer
:
public static void main(String[] args) throws Exception {
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = Stream.generate(sourceIterator::next);
targetStream.forEach(System.out::println);
}
Cependant, je reçois un NoSuchElementException
(car il n'y a pas d'invocation de hasNext
)
Exception in thread "main" java.util.NoSuchElementException
at java.util.AbstractList$Itr.next(AbstractList.java:364)
at Main$$Lambda$1/1175962212.get(Unknown Source)
at java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef.tryAdvance(StreamSpliterators.java:1351)
at java.util.Spliterator.forEachRemaining(Spliterator.java:326)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at Main.main(Main.java:20)
J'ai regardé StreamSupport
et Collections
mais je n'ai pas trouver quoi que ce soit.
- double possible de Comment créer un courant infini<E> d'un Iterator<E>?
- euh je ne veux pas créer un "Infini" Flux".
- qui n'a pas d'importance dans l'affaire.
Stream.generate(iterator::next)
œuvres ?- Cela ne fonctionnera pas pour un fini itérateur.
- Voir stackoverflow.com/questions/23114015/...
- merci pour le lien
Vous devez vous connecter pour publier un commentaire.
Est une façon de créer un Spliterator de l'itération et de l'utiliser comme base pour votre stream:
Une alternative qui est peut-être plus lisible est d'utiliser un objet iterable - et la création d'un objet iterable à partir d'un Itérateur est très facile avec les lambdas parce que Itérable est une interface fonctionnelle:
view
de l'itérateur ou une copie ?sourceIterator.next()
avant d'utiliser le flux de données et vous verrez l'effet (le premier élément ne sera pas vu par le cours d'eau).Spliterator.ORDERED
également être valable charasteric pour tout itérateur?spliteratorUnknownSize
méthode. J'ai modifié.Iterable<String> iterable = () -> sourceIterator;
. Je dois admettre qu'il m'a fallu un certain temps pour comprendre.Supplier<Iterable<String>>
?Iterable<T>
est unFunctionalInterface
qui a une seule méthode abstraiteiterator()
. Donc() -> sourceIterator
est une expression lambda de l'instanciation de l'Iterable
instance anonyme de mise en œuvre.() -> sourceIterator;
est une forme abrégée denew Iterable<>() { @Override public Iterator<String> iterator() { return sourceIterator; } }
Iterable<String> iterable = Arrays.asList("A", "B", "C")::iterator; Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);
Depuis la version 21, Goyave bibliothèque fournit
Ruisseaux.flux(itérateur)
Il fait ce que @assylias's réponse montre.
Très bonne suggestion!
Voici mon réutilisable de prendre sur elle:
Et de l'usage (assurez-vous de manière statique à l'importation asStream):
C'est possible en java 9 en utilisant rien mais des ruisseaux, il y a cependant un bémol à regarder dehors pour. La suite naïf exemple ne parviennent pas à imprimer le dernier élément de l'itérateur.
Ceci, cependant, ne fonctionne pas correctement:
Créer
Spliterator
deIterator
à l'aide deSpliterators
classe contient plus d'une fonction permettant de créer des spliterator, par exemple ici, le matin à l'aidespliteratorUnknownSize
, qui reçoit l'itérateur comme paramètre, puis de créer des Flux de l'aideStreamSupport
Utilisation
Collections.list(iterator).stream()...