为什么foreach lambda比其他循环慢得多?

时间:2014-01-03 11:58:43

标签: java optimization foreach lambda java-8

我有需要迭代的列表。我使用的是Java 8中的新foreach。我发现它比旧的不那么优雅的方法慢得多。我已经阅读了this堆栈讨论,其中更多地关注最佳实践而不是真实世界的实现。我理解,对于lambda来说,还有额外的开销来源于方法传递,但我仍然不理解第一个和第三个案例之间的差异,并且我认为我可能错误地使用它。还没有为lambda实现优化,还是有更好的方法可以使用它们来获得更高的性能?下面是一个示例性示例,而不是我的实际代码。

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Main {
        public static void main(String[] args) {

            List<Memes> memesList =
                    Arrays.asList(
                            new OldMemes(),
                            new TrendingMemes()
                    );

            //----------------------------Benchmark
            long start, end;
            start = System.nanoTime();
            System.out.format("for each started @%d\n", start);
            //Old way.
            for(Memes memes : memesList){
                memes.showMeme();
            }
            //-----------------------------Benchmark
            end = System.nanoTime();
            System.out.println((end - start));
            start = System.nanoTime();
            System.out.format("for started @%d\n", start);
            //Other way
            for(Iterator<Memes> i = memesList.iterator(); i.hasNext(); ) {
                i.next().showMeme();
            }
            //-----------------------------Benchmark
            end = System.nanoTime();
            System.out.println((end - start));
            start = System.nanoTime();
            System.out.format("for each lambda started @%d\n", start);

            //New way.
            memesList.forEach((memes) -> memes.showMeme());

            //-----------------------------Benchmark
            end = System.nanoTime();
            System.out.println((end - start));
            System.out.format("end @%d\n", end);
        }
    interface Memes {
        public void showMeme();
    }

    static class OldMemes implements Memes {

        @Override
        public void showMeme() {
            System.out.println("Id appetere senserit his, nonumes consulatu vel id.");
        }

    }

    static class TrendingMemes implements Memes {

        @Override
        public void showMeme() {
            System.out.println("Id appetere senserit his, nonumes consulatu vel id.");
        }
    }
}

1 个答案:

答案 0 :(得分:9)

您的基准测试非常错误。您只为这两种技术应用一个循环(仅两个元素)。你应该重复这个至少一万亿次。同时增加数组的大小,使用至少50个元素。接下来,在基准测试时不要打印到stdout。这需要花费太多时间并且是同步操作,并且会产生错误的结果。

阅读此主题以获得更好的结果:How do I write a correct micro-benchmark in Java?