web-dev-qa-db-ja.com

Java StreamをScala Stream?

JavaコードをScalaコードに変換する努力の一環として、Java stream Files.walk(Paths.get(ROOT)) Scalaへ。グーグルで解決策を見つけることができません。asScalaはそれをしません。

関連するコードは次のとおりです。

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

javaでは、Files.walk(Paths.get(ROOT))戻り値の型は_Stream<Path>_です。

19
TeeKai

互換性のあるレイヤーや前述の実験的な2.11の機能を必要とせずに、少し良い方法があります here by @ marcospereira

基本的にはイテレーターを使用するだけです:

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

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

Java 8ストリームとScalaストリームは概念的に異なるものです。 Java 8ストリームはコレクションではないため、通常のコレクションコンバーターは機能しません。 scala-Java8-compatgithub )ライブラリを使用して、Java St​​reamsにtoScalaメソッドを追加できます。

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

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

Javaからこの変換(Java-> Scala)を実際に使用することはできません。したがって、Javaからこれを行う必要がある場合は、ストリームを実行してScalaストリームを構築する方が簡単です(それでも厄介です)自分(前述のライブラリが内部で行っていること):

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

ただし、どちらの方法でもJava St​​reamを完全に消費するため、Scala St​​reamに変換することで遅延評価の利点を得ることはできず、直接変換することもできます。ベクトルに。 Scala関数リテラル構文のみを使用する場合は、さまざまな方法でこれを実現できます。同じライブラリーを使用して、コレクションコンバーターに似た関数コンバーターを使用できます。

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)

あるいは、2.11以降、Scalaは-Xexperimentalフラグの下でSAMタイプを実験的にサポートしています。これは、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

Scala 2.13を開始すると、標準ライブラリには scala.jdk.StreamConverters が含まれ、Java to Scala暗黙的なストリーム変換を提供します。

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>

LazyListsはScala 2.13Streamに名前が変更されているため、Streamの使用に注意してください(LazyListとは対照的)。

4
Xavier Guihot