Java 8流产生的代码是否比普通命令式循环慢? [英] Do Java 8 streams produce slower code than plain imperative loops?

查看:98
本文介绍了Java 8流产生的代码是否比普通命令式循环慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

关于函数式编程,尤其是新的Java 8 stream API的宣传太多了.广告宣传它是旧的良好循环和命令式范例的良好替代品. 确实,有时它看起来不错,并且做得很好.但是性能呢?

There are too much hype about functional programming and particularly the new Java 8 streams API. It is advertised as good replacement for old good loops and imperative paradigm. Indeed sometimes it could look nice and do the job well. But what about performance?

例如这是关于此的好文章: Java 8:没有更多的循环 使用循环,您可以一次迭代完成所有工作.但是使用新的流API时,您将链接多个循环,这会使循环变慢得多(对吗?). 看他们的第一个样本.在大多数情况下,循环甚至不会遍历整个数组.但是,要使用新的流API进行过滤,您必须遍历整个数组以过滤出所有候选对象,然后才能获得第一个候选对象.

E.g. here is the good article about that: Java 8: No more loops Using the loop you can do all the job with a one iteration. But with a new stream API you will chain multiple loops which make it much slower(is it right?). Look at their first sample. Loop will do not walk even through the whole array in most cases. However to do the filtering with a new stream API you have to cycle through the whole array to filter out all candidates and then you will be able to get the first one.

在本文中提到了一些懒惰:

In this article it was mentioned about some laziness:

我们首先使用filter操作查找具有Java标记的所有文章,然后使用findFirst()操作获得第一个匹配项.由于流是惰性的,并且filter返回流,因此该方法仅处理元素,直到找到第一个匹配项为止.

We first use the filter operation to find all articles that have the Java tag, then used the findFirst() operation to get the first occurrence. Since streams are lazy and filter returns a stream, this approach only processes elements until it finds the first match.

作者对此懒惰意味着什么?

What does author mean about that laziness?

我做了简单的测试,结果表明,旧的良好循环解决方案可以比流方法快10倍.

I did simple test and it shows that old good loop solution works 10x fast then stream approach.

public void test() {
    List<String> list = Arrays.asList(
            "First string",
            "Second string",
            "Third string",
            "Good string",
            "Another",
            "Best",
            "Super string",
            "Light",
            "Better",
            "For string",
            "Not string",
            "Great",
            "Super change",
            "Very nice",
            "Super cool",
            "Nice",
            "Very good",
            "Not yet string",
            "Let's do the string",
            "First string",
            "Low string",
            "Big bunny",
            "Superstar",
            "Last");

    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000000; i++) {
        getFirstByLoop(list);
    }
    long end = System.currentTimeMillis();

    System.out.println("Loop: " + (end - start));

    start = System.currentTimeMillis();
    for (int i = 0; i < 100000000; i++) {
        getFirstByStream(list);
    }
    end = System.currentTimeMillis();

    System.out.println("Stream: " + (end - start));
}

public String getFirstByLoop(List<String> list) {

    for (String s : list) {
        if (s.endsWith("string")) {
            return s;
        }
    }

    return null;
}

public Optional<String> getFirstByStream(List<String> list) {
    return list.stream().filter(s -> s.endsWith("string")).findFirst();
}

结果是:

循环:517

流:5790

顺便说一句,如果我将使用String []而不是List,则差异将更大!差不多100倍!

BTW if I will use String[] instead of List the difference will be even more! Almost 100x!

问题:如果我正在寻找最佳的代码性能,是否应该使用旧的循环命令式方法? FP范式仅仅是为了使代码更简明易读",而不是关于性能吗?

QUESTION: Should I use old loop imperative approach if I'm looking for the best code performance? Is FP paradigm is just to make code "more concise and readable" but not about performance?

OR

我有什么想念的吗,新的流API至少可以和循环命令方法一样有效?

is there something I missed and new stream API could be at least the same as efficient as loop imperative approach?

推荐答案

问题:如果我要寻找最佳的代码性能,是否应该使用旧的循环命令式方法?

QUESTION: Should I use old loop imperative approach if I'm looking for the best code performance?

现在,可能是的.各种基准似乎表明,在大多数测试中,流的速度比循环慢.虽然不是灾难性地慢.

Right now, probably yes. Various benchmarks seem to suggest that streams are slower than loops for most tests. Though not catastrophically slower.

计数器示例:

  • 在某些情况下,并行流可以提高速度.

  • In some cases, parallel streams can give a useful speed up.

惰性流可以为某些问题提供性能上的好处;参见 http://java.amitph.com/2014/01/java-8-streams-api-laziness.html

Lazy streams can provide performance benefits for some problems; see http://java.amitph.com/2014/01/java-8-streams-api-laziness.html

可以用循环来做等效的事情,而不能用 just 循环来做.

It is possible to do equivalent things with loops, you can't do it with just loops.

但是最重要的是,性能很复杂,而且流还不是提高代码速度的灵丹妙药.

But the bottom line is that performance is complicated and streams are not (yet) a magic bullet for speeding up your code.

FP范式仅仅是为了使代码更简洁易读",而不是关于性能吗?

Is FP paradigm is just to make code "more concise and readable" but not about performance?

不完全是. FP范例确实更加简洁,并且(对于熟悉它的人来说)更具可读性.

Not exactly. It is certainly true that the FP paradigm is more concise and (to someone who is familiar with it) more readable.

但是,通过使用FP范式表达您,您表达它的方式可能会被优化,而使用循环和赋值表达的代码更难实现. FP代码也更适合形式方法.即正式的正确性证明.

However, by expressing the using the FP paradigm, you are also expressing it in a way that potentially could be optimized in ways that are much harder to achieve with code expressed using loops and assignment. FP code is also more amenable to formal methods; i.e. formal proof of correctness.

这篇关于Java 8流产生的代码是否比普通命令式循环慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆