如何将 Java 流转换为 Scala 流?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38339440/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 08:29:15  来源:igfitidea点击:

How to convert a Java Stream to a Scala Stream?

scalajava-8scala-java-interop

提问by TeeKai

As a part of an effort of converting Java code to Scala code, I need to convert the Java stream Files.walk(Paths.get(ROOT))to Scala. I can't find a solution by googling. asScalawon't do it. Any hints?

作为将 Java 代码转换为 Scala 代码的一部分,我需要将 Java 流转换Files.walk(Paths.get(ROOT))为 Scala。我无法通过谷歌搜索找到解决方案。asScala不会做。任何提示?

The followings is the related code:

以下是相关代码:

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

where the Files.walk(Paths.get(ROOT))return type is Stream<Path>in Java.

Files.walk(Paths.get(ROOT))返回类型是Stream<Path>在Java中。

回答by mirosval

There is a slightly nicer way without needing the compat layer or experimental 2.11 features mentioned hereby @marcospereira

有而不需要compat的层或提及的实验2.11特征略有更好的方式在这里通过@marcospereira

Basically just use an iterator:

基本上只使用迭代器:

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

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

回答by knutwalker

Java 8 Streams and Scala Streams are conceptually different things; the Java 8 Stream is not a collection, so the usual collection converter won't work. You can use the scala-java8-compat(github) library to add a toScalamethod to Java Streams:

Java 8 Streams 和 Scala Streams 在概念上是不同的东西;Java 8 Stream 不是集合,因此通常的集合转换器不起作用。您可以使用scala-java8-compat( 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]

You can't really use this conversion (Java->Scala) from Java, so if you have to do this from Java, it's easier (but still awkward) to just run the stream and build the Scala Stream yourself (which is what the aforementioned library is doing under the hood):

您不能真正从 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();

However, both ways will fully consume the Java Stream, so you don't get the benefit of the lazy evaluation by converting it to a Scala Stream and might as well just convert it directly to a Vector. If you just want to use the Scala function literal syntax, there different ways to achieve this. You could use the same library to use function converters, similar to collection converters:

但是,这两种方式都将完全消耗 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)

Alternatively since 2.11, Scala has experimental support for SAM types under the -Xexperimentalflag. This will be non-experimental without a flag in 2.12.

或者,从 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@589838eb

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

回答by Xavier Guihot

Starting Scala 2.13, the standard library includes scala.jdk.StreamConverterswhich provides Java to Scala implicit stream conversions:

开始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@51b1d486
javaStream.toScala(LazyList)
// scala.collection.immutable.LazyList[java.nio.file.Path] = LazyList(?)
javaStream.toScala(Iterator)
// Iterator[java.nio.file.Path] = <iterator>

Note the usage of LazyList(as opposed to Stream) as Streams have been renamed LazyListin Scala 2.13.

需要注意的使用LazyList(而不是Stream)作为Stream■找被重命名LazyListScala 2.13