Supposons que vous souhaitiez diffuser les éléments d’un iterator. Prenons un exemple concret de Scanner
, qui implémente Iterator
.
Étant donné un Iterator
, dites:
// Scanner implements Iterator Iterator scanner = new Scanner(System.in);
Les options pour créer un Stream
partir de celui-ci sont les plus maladroites:
StreamSupport.stream( Spliterators.spliteratorUnknownSize(scanner, Spliterator.ORDERED), false);
ou légèrement plus concis, mais obtus:
StreamSupport.stream( ((Iterable) () -> new Scanner(System.in)).spliterator(), false);
Existe-t-il une méthode usine quelque part dans le JDK qui renvoie un Stream
un Iterator
?
Je voudrais simplement utiliser Stream.generate(iterator::next)
. Oui, il s’agit d’un stream infini, mais le scanner de System.in
, à moins que vous ne sachiez combien de lignes vous demandez, auquel cas il est assez facile à utiliser.
Stream.generate(iterator::next).limit(numLines);
Cela évite à l’iterator d’être itéré deux fois (une fois en tant qu’iterator, une fois en tant que stream).
Si vous avez besoin d’un stream de taille sans savoir sa taille, mais que vous ne voulez pas encombrer votre code, créez simplement une méthode utilitaire prenant explicitement un Iterable
:
public static Stream stream(Iterable it){ return StreamSupport.stream(it.spliterator(), false); }
Cela finit par être plus lisible que d’essayer de tout mettre sur une seule ligne, et ensuite vous pouvez simplement appeler stream(()->iterator);
ou stream(()->new Scanner(System.in));
Vous pouvez également append assez facilement la seconde méthode de commodité:
public static Stream stream(Iterator it){ return stream(()->it); }
vous permettant d’appeler stream(iterator);
ou stream(new Scanner(System.in));
Bien que, si je devais lire System.in
dans un stream, j’utiliserais probablement un Reader plutôt qu’un Scanner:
return new BufferedReader(new InputStreamReader(System.in)).lines();