首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Scala和Java8一样有中间/终端操作吗?

Scala和Java8一样有中间/终端操作吗?
EN

Stack Overflow用户
提问于 2015-07-27 23:17:27
回答 2查看 353关注 0票数 12

在Java8中

当我编写这样的代码时:

代码语言:javascript
复制
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 -实际操作(底层迭代)是在终端ops中完成的,而每个中间操作附加了自己的-let me名称it- Apply内部类。

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

来自JDK8的示例代码:

代码语言:javascript
复制
@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));
                }
            };
        }
    };
}

在斯卡拉

当我编写这样的代码时:

代码语言:javascript
复制
val xs = List(1, 3, 5, 6, 7, 10) 
xs map (x => x * x) filter (x => x > 15) foreach (println)

我已经阅读了一段时间,但我从未明确地听说过这样的术语,而且,SDK实现循环(使用递归或常规循环)在每个操作上都是这样的:

代码语言:javascript
复制
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实现会更快。(O(n) in JavaO(倍数n) in Scala)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-07-28 00:54:25

Java 8流是Scala迭代器的特性较少的同义词,除了它们的并行计算能力外.

如果您不需要并行计算(而且大多数情况下,开销不值得-仅对于大型昂贵的任务才需要并行计算),那么您可以使用Scala中的.iterator (然后是to[Vector]或其他您想要的东西)进行相同的处理。

Java8流是手动专用的(Scala Iterator不是),所以有些用例它们要快得多,但这并不是因为在此过程中重新创建集合所产生的常数因素--至少,如果您在其中抛出一个.iterator。(如果没有.iterator,Scala集合在默认情况下会急切地进行评估;Java集合没有这个选项。)

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

代码语言:javascript
复制
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,这样您就不必每次想要使用它时都要重新创建处理链。例如,用你的平方,你可以

代码语言:javascript
复制
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)

然而,对于Java8流,xsq将在第一个终端操作之后耗尽。

因此Scala实际上完成了Java 8流所做的所有事情(除了并行性),而且还有更多,而且很长一段时间都是如此。

Scala也有并行化集合,但是Java 8实现在性能上有足够的优势,因此我建议首先使用它们。而且,如果手动专门化是您的专长,那么Java 8流具有Int、Double和Long的特性,这是性能上的一大胜利。(注意:使用asList的示例并不是手动专用的。)

但是,如果您只想对操作排队,而不需要构建中间集合的开销,Scala就会这样做。你只要问问就行了。

票数 12
EN

Stack Overflow用户

发布于 2015-07-27 23:31:28

Scala中的列表非常迫切,这意味着(正如您所说)列表上有多个迭代。(至少)有两种方法可以解决这个问题。

使用视图:

代码语言:javascript
复制
xs.view.map(x => x * x).filter(x => x > 15).force

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

代码语言:javascript
复制
xs.toStream.map(x => x * x).filter(x => x > 15)
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31664918

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档