Muh*_*edy 11 java scala java-8 java-stream
当我写这样的代码时:
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 Java
vs 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就会这样做.你只需要问.
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)