web-dev-qa-db-fra.com

Comment convertir un flux Java en un flux Scala?

Dans le cadre d'un effort de conversion de Java code en Scala code, je dois convertir le Java stream _ Files.walk(Paths.get(ROOT)) à Scala. Je ne trouve pas de solution en recherchant sur Google. asScala ne le fera pas. Des conseils?

Ce qui suit est le code associé:

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;

import Java.io.IOException;
import Java.nio.file.Files;
import Java.nio.file.Paths;
import Java.util.stream.Collectors;

....
   Files.walk(Paths.get(ROOT))
            .filter(path -> !path.equals(Paths.get(ROOT)))
            .map(path -> Paths.get(ROOT).relativize(path))
            .map(path -> linkTo(methodOn(FileUploadController.class).getFile(path.toString())).withRel(path.toString()))
            .collect(Collectors.toList()))

où le type de retour Files.walk(Paths.get(ROOT)) est Stream<Path> en Java.

20
TeeKai

Il existe un moyen légèrement plus agréable sans avoir besoin de la couche compat ou des fonctionnalités 2.11 expérimentales mentionnées ici par @ marcospereira

Fondamentalement, utilisez simplement un itérateur:

import Java.nio.file.{Files, Paths}
import scala.collection.JavaConverters._

Files.list(Paths.get(".")).iterator().asScala
31
mirosval

Les flux Java 8 et Scala les flux sont conceptuellement différents; le flux Java 8 n'est pas une collection, donc le convertisseur de collection habituel ne fonctionnera pas. Vous pouvez utiliser la bibliothèque scala-Java8-compat ( github ) pour ajouter une méthode toScala à Java Streams:

import scala.compat.Java8.StreamConverters._
import Java.nio.file.{ Files, Path, Paths }

val scalaStream: Stream[Path] = Files.walk(Paths.get(".")).toScala[Stream]

Vous ne pouvez pas vraiment utiliser cette conversion (Java-> Scala) à partir de Java, donc si vous devez le faire à partir de Java, il est plus facile (mais toujours maladroit) d'exécuter simplement le flux et de construire le Scala Stream vous-même (ce que fait la bibliothèque susmentionnée sous le capot):

import scala.collection.immutable.Stream$;
import scala.collection.mutable.Builder;
import Java.nio.file.Files;
import Java.nio.file.Path;
import Java.nio.file.Paths;
import Java.util.stream.Stream;

final Stream<Path> stream = Files.walk(Paths.get("."));
final Builder<Path, scala.collection.immutable.Stream<Path>> builder = Stream$.MODULE$.newBuilder();
stream.forEachOrdered(builder::$plus$eq);
final scala.collection.immutable.Stream<Path> result = builder.result();

Cependant, les deux façons consomment entièrement le flux Java, de sorte que vous ne bénéficiez pas de l'évaluation paresseuse en le convertissant en un flux Scala et que vous pouvez tout aussi bien le convertir directement à un vecteur. Si vous souhaitez simplement utiliser la syntaxe littérale de la fonction Scala, il existe différentes façons d'y parvenir. Vous pouvez utiliser la même bibliothèque pour utiliser des convertisseurs de fonctions, similaires aux convertisseurs de collection:

import scala.compat.Java8.FunctionConverters._
import Java.nio.file.{ Files, Path, Paths }

val p: Path => Boolean = p => Files.isExecutable(p)
val stream: Java.util.stream.Stream[Path] = Files.walk(Paths.get(".")).filter(p.asJava)

Alternativement depuis 2.11, Scala a un support expérimental pour les types SAM sous le drapeau -Xexperimental. Ce sera non expérimental sans indicateur en 2.12.

$ scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_92).
Type in expressions for evaluation. Or try :help.

scala> import Java.nio.file.{ Files, Path, Paths }
import Java.nio.file.{Files, Path, Paths}

scala> Files.walk(Paths.get(".")).filter(p => Files.isExecutable(p))
<console>:13: error: missing parameter type
       Files.walk(Paths.get(".")).filter(p => Files.isExecutable(p))
                                         ^

scala> :set -Xexperimental

scala> Files.walk(Paths.get(".")).filter(p => Files.isExecutable(p))
res1: Java.util.stream.Stream[Java.nio.file.Path] = Java.util.stream.ReferencePipeline$2@589838eb

scala> Files.walk(Paths.get(".")).filter(Files.isExecutable)
res2: Java.util.stream.Stream[Java.nio.file.Path] = Java.util.stream.ReferencePipeline$2@185d8b6
10
knutwalker

Démarrage Scala 2.13, la bibliothèque standard comprend scala.jdk.StreamConverters qui fournit Java à Scala conversions de flux implicites:

import scala.jdk.StreamConverters._

val javaStream = Files.walk(Paths.get("."))
// javaStream: Java.util.stream.Stream[Java.nio.file.Path] = Java.util.stream.ReferencePipeline$3@51b1d486
javaStream.toScala(LazyList)
// scala.collection.immutable.LazyList[Java.nio.file.Path] = LazyList(?)
javaStream.toScala(Iterator)
// Iterator[Java.nio.file.Path] = <iterator>

Notez l'utilisation de LazyList (par opposition à Stream) car Streams ont été renommés LazyList dans Scala 2.13.

4
Xavier Guihot