Java 8的For与Stream的性能差距到底有多大?

Java 8开始引入了Stream流式操作,终于稍微可以像写Python一样写代码了,不用满大街写For语句了,但是因为这篇文章的缘故,导致我对它的性能一直抱有怀疑态度。

但是仔细分析示例中的代码,其实会发现虽然它的示例代码中使用了Stream但是其实那个很慢的结果真正大部分的时间都花在了Integer的自动装、拆箱操作上,真正的Java 8应该是怎么写这个代码呢,还是自己动手试验一下好了。


package org.acgeek;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;

public class ForVsStream {
    public static void main(String[] args) {
        List<long> forTest = new ArrayList<>();
        List<long> streamTest = new ArrayList<>();

        IntStream.range(0, 100).forEach(n -> {
            int[] a = new Random().ints(5000000, 1, 99999999).toArray();
            int e = a.length;
            int m = Integer.MIN_VALUE;

            long thisTime = System.nanoTime();
            for (int i = 0; i < e; i++)
                if (a[i] > m) m = a[i];
            System.out.println("MAX is " + m);
            Long testRes = System.nanoTime() - thisTime;
            forTest.add(testRes);
            System.out.println("For use time :" + testRes);

            System.out.println(IntStream.of(a).toArray().length);

            thisTime = System.nanoTime();
            // m = IntStream.of(a).max().orElse(0);
            // m = IntStream.of(a).reduce(Integer::max).orElse(0);
            m = IntStream.of(a).reduce(0, (x, y) -> x > y ? x : y);
            System.out.println("MAX is " + m);
            testRes = System.nanoTime() - thisTime;
            streamTest.add(testRes);
            System.out.println("StreamSimple use time :" + testRes);
        });

        Long forTotal = forTest.stream().reduce(0L, Long::sum);
        Long streamTotal = streamTest.stream().reduce(0L, Long::sum);
        System.out.println("For total cost: " + forTotal
                + ", min cost: " + forTest.stream().reduce(Long::min).orElse(0L) + ", average cost : " + forTotal / 100);
        System.out.println("Stream total cost: " + streamTotal
                + ", min cost: " + streamTest.stream().reduce(Long::min).orElse(0L) + ", average cost : " + streamTotal / 100);
    }
}

其实Stream避免反复拆装箱的话使用IntStream就可以了,Java本身为了避免出现这种装箱损耗就提供了这个工具,同时也没有必要自己写reduce函数,直接max就出结果了,但是实际上的结果是reduce更快……

因为考虑到Java的GIT优化可能性,把代码循环执行了100次。求最小值和平均值查看结果

在我这里i5 3.5G 4Core + JDK 1.8.0.102的环境下结果如下:

For total cost: 185314695, min cost: 1309517, average cost : 1834798
Stream total cost: 164412393, min cost: 1291691, average cost : 1627845

所以,Stream其实比For还要快,前提是你要用对方法。

评论

此博客中的热门博文

远程记录OpenWRT日志

用OpenWRT打造自动翻墙路由器(详解篇)

转一下关于Fuck的用法