java - Scala 是否像 Java8 一样具有中间/终端操作?

标签 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);

Java8 流分为两部分;中间操作与终端操作,其中 -AFAIK - 实际操作(底层迭代)在终端操作中完成,而每个中间操作附加其自己的 - 让我命名 - Apply 内部类.

这样,列表将只有一次迭代。

来自 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));
                }
            };
        }
    };
}

在斯卡拉

当我写这样的代码时:

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

我已经阅读了一段时间,但我从来没有明确地听说过这样的术语,而且,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)
}

我的问题是:

我们可以考虑在同一事物上使用 Java 实现会快得多吗? (Java 中的O(n) vs Scala 中的O(n 的倍数))

最佳答案

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)

这里使用 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)

而对于 Java 8 流,xsq 将在第一次终端操作后耗尽。

所以 Scala 实际上做了 Java 8 流做的所有事情(除了并行性),而且还做了很多,而且已经持续了很长时间。

Scala 也有并行化集合,但 Java 8 实现在性能上足够优越,在这一点上我建议首先使用它们。同样,如果您喜欢手动特化,Java 8 流可以为 Int、Double 和 Long 提供它,这是一个巨大的性能胜利。 (注意:您的示例使用 asList,不是手动专门化的。)

但是,如果您只想对操作进行排队,而没有构建中间集合的开销,Scala 可以做到。你只需要问。

关于java - Scala 是否像 Java8 一样具有中间/终端操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31664918/

相关文章:

java - 为什么这里是 ExceptionInInitializerError?

java - Android Java如何制作单条形图

java - 如何在 Apache Camel 中结合 Redelivery 策略和 Hystrix 断路器?

java - 为什么按钮在点击时调整大小

java - 如何将两个集合项目与项目组成?

java - JDK 1.7 允许自定义 taglet 的名称*以点开头*。 JDK 1.8 禁止它?

java - 为什么这个并发执行总是给我相同的跟踪?

mongodb - 没有可用的隐式 View

regex - 如何有条件地从 Scala 数据框中的列中的字符串中删除文本?

scala - 新的 play-2.1.1 安装中缺少 sbt/boot/directory。在 Linux Mint 14 上安装 Playframework