Java中多种循环性能的区别比较

培训教学 潘老师 7个月前 (10-10) 172 ℃ (0) 扫码查看

Java提供了许多迭代列表的方法。其中一些方法包括:

我们不会详细讨论上述每种方法的基本知识,因为这超出了本文的范围,而且大多数人都已经很了解。

在本文中,我们将比较所有循环方法针对相同的数据集的相对性能。

1.遍历列表的不同方法

我们列出了我所知的4种不同的方法。

1.1. Stream API

Java 8 Stream API提供了一种迭代集合并对每个元素进行操作的方式。流可以用作for循环的替代方法。

private static List<Integer> list = new ArrayList<>();
list.stream().forEach(consumerAction);

1.2. 增强型for循环

在这种技术中,使用Java 5中引入的高级for-each语句。

private static List<Integer> list = new ArrayList<>();
for(Integer i : list)
{
    // do other stuff
}

1.3. ListIterator接口

private static List<Integer> list = new ArrayList<>();
list.listIterator().forEachRemaining(consumerAction);

1.4. 简单for循环

private static List<Integer> list = new ArrayList<>();
int size = list.size();
for(int j = 0; j < size ; j++)
{
    //do stuff
}

2.性能比较

我们创建了一个ArrayList,并将其填充了一百万个整数实例。然后,我们将使用所有上述方法来遍历列表。这样我们就能够了解性能差异。

2.1. 执行环境

  • Java 16
  • Eclipse 2021-06

2.2. 源代码

import java.util.ArrayList;
import java.util.List;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.infra.Blackhole;
public class ForLoopPerformanceTest
{
    public static void main(String[] args) throws Exception {
        org.openjdk.jmh.Main.main(args);
    }
    private static List<Integer> list = new ArrayList<>();
    static
    {
        for(int i=0; i < 1_000_000; i++)
        {
            list.add(i);
        }
    }
    @Benchmark
    @Fork(value = 1, warmups = 1)
    @BenchmarkMode(Mode.Throughput)
    public void usingStream(Blackhole blackhole) {
        list.stream().forEach(i -> blackhole.consume(i));
    }
    @Benchmark
    @Fork(value = 1, warmups = 1)
    @BenchmarkMode(Mode.Throughput)
    public void usingIterator(Blackhole blackhole) {
        list.listIterator().forEachRemaining(i -> blackhole.consume(i));
    }
    @Benchmark
    @Fork(value = 1, warmups = 1)
    @BenchmarkMode(Mode.Throughput)
    public void usingForEachLoop(Blackhole blackhole) {
        for(Integer i : list)
        {
           blackhole.consume(i);
        }
    }
    @Benchmark
    @Fork(value = 1, warmups = 1)
    @BenchmarkMode(Mode.Throughput)
    public void usingSimpleForLoop(Blackhole blackhole) {
        for(int i = 0; i < list.size() ; i++)
        {
            blackhole.consume(list.get(i));
        }
    }
}

当基于JMH的基准运行时,控制台中的输出如下:

Benchmark                                   Mode  Cnt    Score    Error  Units
ForLoopPerformanceTest.usingForEachLoop    thrpt   20  259.008 ± 17.888  ops/s
ForLoopPerformanceTest.usingIterator       thrpt   20  256.016 ± 10.342  ops/s
ForLoopPerformanceTest.usingSimpleForLoop  thrpt   20  495.308 ± 12.866  ops/s
ForLoopPerformanceTest.usingStream         thrpt   20  257.174 ± 15.880  ops/s

显然,使用简单的for循环在性能上要远远领先。其余三种方法提供了类似的性能数字。

3.结论

尽管简单的for循环提供了最佳性能,但其他循环方法提供了更好的可读性。

此外,我们正在使用包含超过百万个项目的列表,这在大多数应用程序中并不是一个非常实际的情况。

因此,如果列表中没有数百万个项目,可以使用新的Java功能,例如Stream API或增强型for循环。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/teach/9417.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】