我正在使用Java * Stream API,我在Lagecy系统中使用了以下代码:
Iterator itr = configMap.entrySet().iterator();
List<String> resultList = new ArrayList<String>();
while(itr.hasNext()){
Entry e = (Entry)itr.next();
Config rc = (Config)e.getValue();
if (rc != null && rc.getVisibleTo() != null && (rc.getVisibleTo().equalsIgnoreCase("0010") || rc.getVisibleTo().equalsIgnoreCase("0111") || rc.getVisibleTo().equalsIgnoreCase("0011"))){
resultList .add(rc.getName());
}
}
我写了以下代码的Stream Equivalent,如下所示:
List<String> resultList = configMap.entrySet()
.parallelStream()
.map(r -> r.getValue())
.filter(r -> r.getVisibleTo() != null)
.filter(r -> {return
r.getVisibleTo().equalsIgnoreCase("0010")
|| r.getVisibleTo().equalsIgnoreCase("0111")
|| r.getVisibleTo().equalsIgnoreCase("0011");
})
.map(r -> r.getName())
.collect(Collectors.toList());
我获得所需结果的方式。我的问题是,在这种情况下,哪种表现明智是更好的写作方式?如果我选择任何一个而不是另一个,我真的会获得任何价值吗?地图中有大约1000个值。
答案 0 :(得分:2)
首先,如果你关心表现,你应该根据事实来决定,所以测量,不要猜测(即使用JMH)。
对于简单的情况,迭代或经典循环往往比Streams更快。另一方面,流可以更快,并且通常可以通过并行性进一步加速(工作负载可以轻松并行化)。在大多数情况下,根据我的经验,它并不重要,因为数据集太小和/或使用它的代码不够性能。
关于可读性/可维护性,我倾向于采用流/功能方法来更好地分离关注点。但是for-each循环也可以改善你的迭代代码。所以没有简单的是/否答案,这完全取决于上下文。
答案 1 :(得分:2)
由于您将此作为并行流编写,尝试多线程并分割工作,因此您可能会看到管理线程的开销导致性能下降,因为您的工作有点小。这里的另一个陷阱是,由于您正在使用CommonForkJoinPool
(此默认线程池),因此阻止使用任务会降低整个应用程序的性能(这虽然不是非常相关),但这不是一个很好的选择。对于你工作的小规模,要记住这一点。
话虽如此,您是否要使用单线程configMap.entrySet().stream()
,我会说性能差异可能会稍微慢一些,但可读性可以弥补它。因此,选择成为稍快的代码或更好的可读性之间的决定,这完全取决于您(但我会亲自选择流)。
答案 2 :(得分:2)
我只是略微重写sream
示例:
List<String> resultList = configMap.entrySet()
.parallelStream()
.map(Map.Entry::getValue)
.filter(Objects::nonNull) // value might be a null
.filter(r ->
((Predicate<String>) "0010"::equals)
.or("0111"::equals) // null-save equivalent to "0111".equals(value)
.or("0011"::equals)
.test(r.getVisibleTo())
)
.map(Config::getName)
.collect(Collectors.toList());
并将使用它。 有关详细的效果说明,请参阅这些问题Java 8: performance of Streams vs Collections和Iterator versus Stream of Java 8
正如@ 4castle在下面的评论中所建议的那样,我们可以使用configMap.values()
代替configMap.entrySet()
来缩短它:
List<String> resultList = configMap.values()
.parallelStream()
.filter(Objects::nonNull)
.filter(r ->
((Predicate<String>) "0010"::equals)
.or("0111"::equals) // null-save equivalent to "0111".equals(value)
.or("0011"::equals)
.test(r.getVisibleTo())
)
.map(Config::getName)
.collect(Collectors.toList());