在 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/