使用lambda表达式可以获得性能提升吗?

时间:2018-04-04 03:55:48

标签: java performance lambda

我需要检查两个列表中是否存在共同元素。我想出了两种方法:

方法01:循环

private boolean func01 (List<String> list1, List<String> list2) {
    for (String group : list1) {
        for (String funcGroup : list2) {
            if (group.equals(funcGroup)) {
                return true;
            }
        }
    }
    return false;
}

方法02:Lambda

private boolean func02 (List<String> list1, List<String> list2) {
    return list1.stream().filter(list2::contains).findAny().isPresent();
}

在我看来,我发现第一种方法更具可读性。我需要了解的是,比较这两种方法时是否存在任何差异或优势?

3 个答案:

答案 0 :(得分:4)

要回答您的直接问题,如果您想知道通过使用lambda表达式是否有性能提升,您应该创建一个微基准测试和测量。

但是,我想指出你的第二个解决方案不仅使用lambda表达式(实际上是方法引用),而且也使用Stream 。通常,由于运行流管道所需的所有基础结构,基于流的解决方案需要更长的时间。然而,在大多数情况下,这些解决方案的扩展也会更好。

现在,关于您的具体问题,检查两个列表中是否存在公共元素的最佳方法是使用自Java 1.5以来可用的Collections.disjoint方法:

return !Collections.disjoint(list1, list2);

答案 1 :(得分:3)

方法1优化:

你不需要2个循环,你可以在匹配时立即返回,所以你在那个时候停止遍历列表 - (例如阳光情况你得到第一个元素的匹配 - 你有1次迭代,最糟糕的情况是你的匹配是最后一个元素 - 你必须遍历整个列表以达到匹配)

private boolean func01 (List<String> list1, List<String> list2) {
        for (String group : list1) {
            if (list2.contains(group)) return true;
        }

        return false;
    }

lambda等效优化:

  • findAny().isPresent() - 获取与谓词匹配的元素的可选项,并检查Optional是否存在 - 这相当于anyMatch(),因为两个表达式都返回boolean

  • filter()将始终遍历整个列表

  • anyMatch()有短路行为 - 意味着它将在第一场比赛中停止

所以你可以把它重写为:

private boolean func02 (List<String> list1, List<String> list2) {
  return list1.stream().anyMatch(list2::contains);
}

回答您的问题 - 这两种方法没有明显的性能差异,会考虑到:

  • 为集合创建流有轻微的开销

  • 流操作可以并行运行(list1.stream().parallel().anyMatch(list2::contains))。例如,在这种情况下,在同一个流上并行线程运行的anyMatch()将定期检查先前的线程是否找到匹配,并将停止遍历集合,而不是继续遍历整个集合。因此理论上对于大量输入列表,您应该通过并行流获得更好的结果。

答案 2 :(得分:2)

例如,您可以找到与非常相关的比较here

一旦代码足够热(第一个会胜利),性能将无关紧要

考虑哪个更易于阅读 - 您的意见是第一个,我的是第二个。一旦你在java-8中使用了流,就没有回头路了。

此外,有多种情况下使用stream-api做事更具可读性,能够并行化。此外,流具有内部不同的优化,使它们非常好。这些优化必须由您主要完成