如何将Java Stream转换为Scala流?

时间:2016-07-12 21:50:51

标签: scala java-8 scala-java-interop

作为将Java代码转换为Scala代码的努力的一部分,我需要将Java流Files.walk(Paths.get(ROOT))转换为Scala。我无法通过Google搜索找到解决方案。 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()))

其中Files.walk(Paths.get(ROOT))返回类型为Java中的Stream<Path>

3 个答案:

答案 0 :(得分:26)

有一种稍微好一点的方法,不需要here

提到的{0}提到的compat图层或实验2.11版功能

基本上只使用迭代器:

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

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

答案 1 :(得分:10)

Java 8 Streams和Scala Streams在概念上是不同的东西; Java 8 Stream不是一个集合,因此通常的集合转换器不起作用。您可以使用scala-java8-compatgithub)库向Java Streams添加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-&gt; 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获得延迟评估的好处,并且可能只是将其直接转换为Vector。如果您只想使用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

答案 2 :(得分:2)

public int getLineNumberFor(String lastName) { char c = lastName.charAt(0); if (c >= 'A' && c <= 'M') { return 1; } else if (c >= 'N' && c <= 'Z') { return 2; } return 0; } 开始,标准库包括Scala 2.13,该库提供Java到Scala的隐式流转换:

scala.jdk.StreamConverters

请注意import scala.jdk.StreamConverters.Ops._ 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> (而不是LazyList)的使用,因为StreamStream中已重命名为LazyList