Je cherche un moyen concis de convertir un Iterator
en Stream
ou plus spécifiquement de "visualiser" 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();
Sur la base des quelques suggestions dans les commentaires, j'ai également essayé d'utiliser Stream.generate
:
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
je n'ai rien trouvé.
Stream.generate(iterator::next)
fonctionne?Réponses:
Une façon consiste à créer un séparateur à partir de l'itérateur et à l'utiliser comme base pour votre flux:
Une alternative qui est peut-être plus lisible est d'utiliser un Iterable - et créer un Iterable à partir d'un Iterator est très facile avec lambdas car Iterable est une interface fonctionnelle:
la source
sourceIterator.next()
avant d'utiliser le flux et vous verrez l'effet (le premier élément ne sera pas vu par le flux).Iterable<String> iterable = () -> sourceIterator;
. Je dois admettre qu'il m'a fallu un certain temps pour comprendre.Iterable<T>
est unFunctionalInterface
qui n'a qu'une seule méthode abstraiteiterator()
. Il en() -> sourceIterator
va de même pour une expression lambda instanciant uneIterable
instance en tant qu'implémentation anonyme.() -> sourceIterator;
une fois, est une forme abrégée denew Iterable<>() { @Override public Iterator<String> iterator() { return sourceIterator; } }
Depuis la version 21, la bibliothèque Guava fournit
Streams.stream(iterator)
Il fait ce que @ assylias l » montre de réponse .
la source
Grande suggestion! Voici ma version réutilisable:
Et l'utilisation (assurez-vous d'importer statiquement asStream):
la source
C'est possible dans Java 9.
la source
.parallel()
flux. Ils semblent également un peu plus lents que d'aller plus loinSpliterator
, même pour une utilisation séquentielle.parallel
peut être génial, la simplicité est incroyable.Créer
Spliterator
àIterator
partir de laSpliterators
classe contient plus d'une fonction pour créer un séparateur, par exemple ici, j'utilisespliteratorUnknownSize
qui obtient l'itérateur comme paramètre, puis créer un flux à l'aideStreamSupport
la source
et utiliser
Streams.stream(iterator)
:la source
Une autre façon de le faire sur Java 9+ en utilisant Stream :: iterate (T, Predicate, UnaryOperator) :
la source
Utilisation
Collections.list(iterator).stream()...
la source