Java包含与anyMatch行为

c7rzv4ha  于 2023-01-29  发布在  Java
关注(0)|答案(2)|浏览(118)

如果我有一个Name对象,并且有一个Namenames)类型的ArrayList,我想确定我的名字列表是否包含一个给定的Name对象(n),我可以用两种方法来做:

boolean exists = names.contains(n);

boolean exists = names.stream().anyMatch(x -> x.equals(n));

我在考虑这两个变量的行为是否相同,然后考虑如果n赋值为null会发生什么?
对于contains,据我所知,如果参数是null,那么如果列表包含null,它将返回true。我将如何实现这个anyMatch-是否使用Objects.equals(x, n)
如果这就是它的工作原理,那么哪种方法更高效-是anyMatch,因为它可以利用惰性和并行性?

a64a0gku

a64a0gku1#

基于流的版本的问题在于,如果集合(以及它的流)包含null元素,那么当 predicate 试图在这个null对象上调用equals时,它将抛出NullPointerException
这可以通过以下方式避免

boolean exists = names.stream().anyMatch(x -> Objects.equals(x, n));

但是在这种情况下,基于流的解决方案并没有什么实际的优势。并行性可能会为 * 真正 * 大的列表带来优势,但不应该随意地在这里或那里添加一些parallel(),假设它 * 可能 * 使事情更快。首先,您应该清楚地识别实际的瓶颈。
就可读性而言,我更喜欢第一个经典的解决方案,如果你想检查names.contains(aParticularValue)的列表,你应该这样做-它读起来像散文,使意图清楚。
编辑
contains方法的另一个优点在评论和其他回答中提到过,在这里可能值得一提:如果names集合的类型后来被改变了,比如,变成了HashSet,那么你将免费获得更快的contains-check(用O(1)代替O(n)),而不需要改变代码的任何其他部分,基于流的解决方案仍然需要迭代 all 个元素,这可能会显著降低性能。

js81xvg6

js81xvg62#

如果以合理的方式编写hashCode()equals(),则它们应提供相同的结果。
但是性能可能会完全不同,对于列表来说,这并不重要,但是对于HashSet,contains()将使用hashCode()来定位元素,并且它将在恒定时间内完成(最有可能),而对于第二种解决方案,它将在所有项上循环并调用一个函数,因此将在线性时间内完成。
如果n为空,实际上并不重要,因为通常equals()方法知道null参数。

相关问题