【发布时间】:2016-01-21 14:58:18
【问题描述】:
我有一个List 的元素,它们之间没有可测量的顺序。它们的属性也很复杂,我不能简单地将它们插入Set(因为不同的属性可能代表相同的元素)。
在我的程序过程中,我分析了列表中的每个元素,并在此基础上添加了其他元素(例如构建图表并转到每个节点以添加其他路径和节点)。但是,他们添加的元素可能等同于List 中的其他元素。在这种情况下,它们不会被添加,并且等效元素的属性已更改(假设是计数器)。
我一直在使用这段代码来查找是否存在等效状态:
public static State stateAlreadyExists(State current) {
for (State any : list) {
if (equivalencyMethod(any, current)) {
return any;
}
}
return null;
}
然而,这段代码虽然有O(n) 的复杂性,但对我的情况来说性能不够。我添加的每个元素都会执行此代码,并且我会为每个分析的元素添加大约 sqrt(N) 元素(因此,例如,分析元素 400 会创建 20 个新元素)。为了提高性能,我使用了 Java 的并行流:
public static State stateAlreadyExists(State current) {
Optional<State> opt = list.parallelStream().filter(
any -> equivalencyMethod(any, current)).findFirst();
if (opt.isPresent()) {
return opt.get();
}
return null;
}
并且性能显着提高。 问题是这段代码并不完全等价,因为我们在返回一个元素之前分析了整个流。大多数情况下,等效元素位于列表的第一个 sqrt(N) 元素中,因此在第一个匹配时停止的方法会更好。
我知道streams 有一个noneFound() 方法。一旦找到匹配项,它就会返回。但是,它返回一个boolean,而不是元素本身。有没有办法使用这个或类似构建的方法来返回找到的第一个匹配项?
根据JavaDoc,findFirst():
返回此流的第一个元素
而 findAny():
选择流中的任何元素。这是为了在并行操作中实现最大性能。
因此,通过使用findAny() 调用,我的代码可以变得更加高效,因为顺序对我的问题并不重要,因为任何时候都只有 1 个等效元素。
【问题讨论】:
-
findFirst()在找到匹配项后立即返回(除非您的流已排序),因此除非必要,否则不会分析整个流。 -
findFirst()不接受任何参数。它只返回流的第一个元素 -
我不明白你最后的评论。第一个元素不是你想要的吗?
-
“因为我们在返回元素之前分析了整个流”——所以你的问题是这个假设,凭空而来,尽管你已经承认了性能提升?
-
我没有意识到
findFirst()可以中断过滤操作
标签: performance java-8 java-stream