Le moyen le plus simple de diffuser un iterator

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();