stream.max()总是比stream.reduce()快吗?

时间:2017-06-02 09:40:01

标签: java lambda java-8 java-stream

我有以下代码段

    // List of persons with name and age
    List<Person> persons = new ArrayList<>();       

    // Adding 10,000 objects
    for(int i = 0 ; i < 10000 ; i ++) {
        Person p = new Person();
        p.setName("Person " + i);
        p.setAge(i);
        persons.add(p);
    }

    long time1 = System.nanoTime();
    System.out.println("Time before steram.reduce()" + time1);
    Optional<Person> o1 = Optional<Person> o1 = persons.stream().reduce(BinaryOperator.maxBy(Comparator.comparingInt(p -> p.getAge())));
    long time2 = System.nanoTime();
    System.out.println(o1.get() + "\nTime after stream.reduce() " + time2);
    System.out.println("**** Rough execution time for stream.reduce() : " + (time2 - time1) + " nano secs");


    long time3 = System.nanoTime();
    System.out.println("Time before stream.max() " + time3);
    Optional<Person> o2 = persons.stream().max((p01, p02) -> p01.getAge() - p02.getAge());
    long time4 = System.nanoTime();
    System.out.println(o2.get() + "\nTime after stream.max() " + time4);
    System.out.println("**** Rough execution time for stream.max() : " + (time4 - time3) + " nano secs");

虽然这可能不是理解执行时间的理想方法,但基本上我在这里要做的是找到最早的Person并打印出使用{{1}找出它的时间} vs stream.reduce()

输出

stream.max()

PS 我已多次运行此代码,更改了Time before steram.reduce()8834253431112 [ Person 9999, 9999] Time after stream.reduce() 8834346269743 **** Rough execution time for stream.reduce() : 92838631 nano secs Time before stream.max() 8834346687875 [ Person 9999, 9999] Time after stream.max() 8834350117000 **** Rough execution time for stream.max() : 3429125 nano secs stream.max()的顺序,发现stream.reduce()需要更多时间才能生成输出比stream.reduce()

stream.max() 总是stream.max()快吗?如果是,那么我们应该何时使用stream.reduce()

2 个答案:

答案 0 :(得分:3)

ReferencePipeline implementation of max如下所示:

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class MaxReducePerformance
{
    public static void main(String[] args)
    {
        for (int n=500000; n<=5000000; n+=500000)
        {
            List<Person> persons = new ArrayList<>();
            for (int i = 0; i < n; i++)
            {
                Person p = new Person();
                p.setName("Person " + i);
                p.setAge(i);
                persons.add(p);
            }

            System.out.println("For " + n);

            long time1 = System.nanoTime();
            Optional<Person> o1 = persons.stream().reduce((p01, p02) -> 
            {
                if (p01.getAge() < p02.getAge())
                    return p02;
                return p01;
            });
            long time2 = System.nanoTime();
            double d0 = (time2 - time1) / 1e9;
            System.out.println("Reduce: "+d0+" seconds, " + o1);

            long time3 = System.nanoTime();
            Optional<Person> o2 =persons.stream().max(
                (p01, p02) -> p01.getAge() - p02.getAge());
            long time4 = System.nanoTime();
            double d1 = (time4 - time3) / 1e9;
            System.out.println("Max   : "+d1+" seconds, " + o2);
        }

    }
}


class Person
{
    String name;
    int age;

    void setName(String name)
    {
        this.name = name;
    }

    void setAge(int age)
    {
        this.age = age;
    }

    int getAge()
    {
        return age;
    }

}

因此,您观察到的任何性能差异只是用于衡量性能的方法的工件。

或者,更明确地说:答案是,它不是&#34;总是更快&#34;。

编辑:仅供参考,以下是您稍微调整过的代码版本。它会反复对不同数量的元素进行测试。 这仍然不是一个真实的,可靠的(Micro)基准测试,但比仅运行整个项目更可靠:

Error:Could not find com.android.tools.build:gradle:3.2.
Searched in the following locations:
    file:/home/bunny/android-studio/gradle/m2repository/com/android/tools/build/gradle/3.2/gradle-3.2.pom
    file:/home/bunny/android-studio/gradle/m2repository/com/android/tools/build/gradle/3.2/gradle-3.2.jar
    https://jcenter.bintray.com/com/android/tools/build/gradle/3.2/gradle-3.2.pom
    https://jcenter.bintray.com/com/android/tools/build/gradle/3.2/gradle-3.2.jar
Required by:
    project :

输出应显示持续时间基本相等。

答案 1 :(得分:0)

您的reduce函数在每次迭代中评估getAge两次,这就是为什么结果可能会慢一些,具体取决于编译器优化,重构代码并检查结果。

此外,Stream.max可能会受益于内置的VM优化,因此您应始终坚持使用内置函数,而不是实现等效函数。