如何将Java流转换为Scala流?

bvjveswy  于 2022-11-09  发布在  Scala
关注(0)|答案(3)|浏览(280)

作为将Java代码转换为Scala代码的一部分,我需要将Java流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;

// ...snip...

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>

e37o9pze

e37o9pze1#

有一种稍微好一点的方法,不需要Comat层或@marCospereira提到的here试验性2.11功能
基本上只需使用迭代器:

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

Files.list(Paths.get(".")).iterator().asScala
goucqfw6

goucqfw62#

Scala 2.13开始,标准库包括scala.jdk.StreamConverters,它提供Java到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>

请注意,Scala 2.13中不推荐使用LazyList(而不是Stream),因为Stream不推荐使用。LazyList是受支持的更换类型。

utugiqy6

utugiqy63#

Java 8流和Scala流在概念上是不同的;Java 8流不是集合,所以通常的集合转换器不起作用。您可以使用scala-java8-comat(github)库将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]

您不能真正从Java使用这个转换(Java->Scala),所以如果您必须从Java执行此操作,那么只运行流并自己构建Scala Stream(这就是前面提到的库在幕后做的事情)会更容易(但仍然很尴尬):

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 Stream,因此您无法通过将其转换为Scala Stream来获得延迟计算的好处,而只需将其直接转换为矢量即可。如果你只想使用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

相关问题