java - 哪种代码在查找列表中的特定元素方面表现更好

标签 java filter java-8 java-stream

有多种方法可以在列表中查找元素。例如,我有一个列表,其中一些元素具有唯一的 ID。对于给定的 ID,我想从列表中返回特定元素。

列表示例(只是架构,不是正确的语法):

//Element(String id, int value)
List<Element> list = new ArrayList();
int elemCount = 1000000;
for(int i = 0; i<elemCount; i++)
    list.add(new Element("id"+i, i));
Collections.shuffle(list);
Element e = getElement("id" + ThreadLocalRandom.current().nextInt(0, elemCount));

给出以下两种方法,根据 java 内部实现,哪种方法通常执行得更好,为什么?

第一种方法:

public Element getElement(String id) {
   return list.stream()
      .filter(e -> e.getId().equals(id))
      .findAny()
      .orElse(null);
}

第二种方法:

public Element getElement(String id) {
   for(Element e : list)
      if(e.getId().equals(id))
         return e;
   return null;
}
  • 选择“元素”作为对象只是为了举例。
  • 不相关:元素的结构和大小、PC 性能等。
  • Java 版本:1.8.0_111

最佳答案

由于我无法根据java内部实现得到答案,所以我为自己做了一个基准测试。

我想与大家分享我得出的结果。我确实为从大小 1 到 1000 的每个列表运行了基准测试。每个列表大小的每个基准测试都运行了 10000 次,并计算平均值以消除错误。

免责声明:我不是基准专家,我只是做了一个简单的实现。结果并非 100% 准确,我得出的结论可能是错误的。如果您能做得更好,请随意改进我的基准,或者自己制作一个基准并将结果发布在新答案中。

您可以在此处找到基准文件:https://github.com/Spenhouet/BenchmarkFindElement

  1. 使用并行流来执行此简单任务会产生更多开销,并且比普通流更慢。
  2. 如果列表已排序并且想要的项目是列表的最后一个, .findFirst().findAny() 更快。​​
  3. 如果列表已排序并且想要的项目是列表的最后一个, 通过使用 .findAny(),“for”方法更快。
  4. 如果列表被打乱并且想要的项目 ID 是随机的 .findFirst().findAny() 没有区别。
  5. 如果列表被打乱并且想要的项目 ID 是随机的,那么“stream”和“for”方法之间只有一点点区别。 “流”方法稍微好一点

使用 Java 版本测试:1.8.0_111

例如,在包含 505 到 575 个项目的打乱列表中查找随机 ID 的性能图。蓝线是“for”方法,红线是“stream”方法。

Benchmark-Graph for subset of items

例如,在具有 1 到 100000 个项目的打乱列表中查找随机 id 的性能图(平均仅为 10 倍)。蓝线是“for”方法,红线是“stream”方法。

Benchmark-Graph for 1 to 100000 items

如果您想查看一些图表/自己生成它们,则只需从上面的 github 链接下载存储库,导入项目并使用 VM 选项 -Xms1024m -Xmx4068m 运行它。

具有 1 到 40000 个列表元素,每个运行 100 次以获得平均值和 VM 选项:-Xms1024m -Xmx4068m -XX:+PrintCompilation -verbose:gc -Xbatch -XX:CICompilerCount=2

Benchmark-Graph for 1 to 40000 items and other VM options

关于java - 哪种代码在查找列表中的特定元素方面表现更好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40280919/

相关文章:

javascript - 我可以使用过滤器从对象数组中提取值吗?

mysql - 根据 ID 过滤数据

JavaFX NumberAxis AutoRange 无限循环

java - 使用 Java 8 简化循环

java - 找不到符号:方法prepareStatement(String)位置:类型连接

java - 如何根据当前秒数获取第二天的第一秒?

Django - 过滤模板中的RelatedManager _set?

java - 以 rx 方式与 Jersey 客户端合作

java - 在Google Appengine中使用MapOnlyMapper时出现RetryHandler异常

java - 在 Java 中将包含命令行参数的字符串拆分为 String[]