Scala是否具有Java8具有的中间/终端操作?

Muh*_*edy 11 java scala java-8 java-stream

在Java8中

当我写这样的代码时:

Stream<Integer> xs = Arrays.asList(1, 3, 5, 6, 7, 10).stream();
xs.map(x -> x * x).filter (x -> x > 15).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

Java8流分为两个部分; 中间与终端操作,其中-AFAIK - 实际操作(引擎内迭代)在终端操作中完成,而每个中间操作都附加自己的-let me name it- 应用内部类.

这样,列表上只会有一次迭代.

JDK8的示例代码:

@Override
@SuppressWarnings("unchecked")
public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
    Objects.requireNonNull(mapper);
    return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
        @Override
        Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
            return new Sink.ChainedReference<P_OUT, R>(sink) {
                @Override
                public void accept(P_OUT u) {
                    downstream.accept(mapper.apply(u));
                }
            };
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

在斯卡拉

当我写这样的代码时:

val xs = List(1, 3, 5, 6, 7, 10) 
xs map (x => x * x) filter (x => x > 15) foreach (println)
Run Code Online (Sandbox Code Playgroud)

我一直在阅读它,但我从未明确地听过这些术语,而且,SDK实现在每个操作上循环(使用递归或常规循环):

final override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That = {
if (bf eq List.ReusableCBF) {
  if (this eq Nil) Nil.asInstanceOf[That] else {
    val h = new ::[B](f(head), Nil)
    var t: ::[B] = h
    var rest = tail
    while (rest ne Nil) {
      val nx = new ::(f(rest.head), Nil)
      t.tl = nx
      t = nx
      rest = rest.tail
    }
    h.asInstanceOf[That]
  }
}
else super.map(f)
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:

我们可以认为同一件事的Java实现会快得多.(O(n) in Javavs O(n的倍数) in Scala)

Rex*_*err 12

Java 8流是Scala迭代器的较少特征完整的表兄弟,除了它们并行计算的能力.

如果你不需要并行计算(并且大多数时候开销都不值得 - 只为你想要的大型昂贵工作),那么你可以.iterator在Scala中获得相同类型的处理(然后to[Vector]或者你想要的任何东西)在末尾).

Java 8流是手动专用的(Scala Iterator不是),因此有些用例会更快,但不是因为沿途重新创建集合的常数因素 - 至少,如果你扔.iterator在那里.(没有.iterator,Scala集合默认情况下急切地评估; Java集合没有那个选项.)

您编写的Java 8代码的Scala等价物如下:

val xsi = Array(1, 3, 5, 6, 7, 10).iterator
xsi.map(x => x*x).filter(_ > 15).foreach(println)
Run Code Online (Sandbox Code Playgroud)

使用Scala与Java创建的集合数量没有差异.

对Scala的Iterator文档采用非常清晰的"终端操作"语言可能是个好主意.Java 8流文档非常棒,因为当您构建工作描述并最终完成工作时,它们会非常清晰.

Scala 提供了一个Stream记忆旧作品的类(因此,如果您重复使用它,则不必再次计算它),以及各种各样的类,views这样您每次要使用它时都不必重新创建处理链.例如,通过你的平方,你可以

val xsv = Array(1, 3, 5, 6, 7, 10).view
val xsq = xsv.map(x => x*x)
xsq.filter(_ > 15).foreach(println)
xsq.filter(_ < 5).foreach(println)
Run Code Online (Sandbox Code Playgroud)

而对于Java 8 xsq,第一个终端操作后流将耗尽.

因此,Scala实际上完成了Java 8流所做的一切(保存并行性),而且还有很长一段时间.

Scala还具有并行化集合,但Java 8实现在性能上足够优越,此时我建议首先使用它们.再说一次,如果你的手工专业化是你的东西,Java 8流将它用于Int,Double和Long,这是一个巨大的性能胜利.(注意:您的示例,使用asList,不是手动专用.)

但是如果你只想排队操作并且没有构建中间集合的开销,Scala就会这样做.你只需要问.


mar*_*ran 9

Scala中的列表非常渴望,这意味着(正如您所说)列表上有多个迭代.有(至少)两种方法来解决这个问题.

使用视图:

xs.view.map(x => x * x).filter(x => x > 15).force
Run Code Online (Sandbox Code Playgroud)

或者通过将列表转换为流(这是懒惰的):

xs.toStream.map(x => x * x).filter(x => x > 15)
Run Code Online (Sandbox Code Playgroud)