如果我有一个Name
对象,并且有一个Name
(names
)类型的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
,因为它可以利用惰性和并行性?
2条答案
按热度按时间a64a0gku1#
基于流的版本的问题在于,如果集合(以及它的流)包含
null
元素,那么当 predicate 试图在这个null
对象上调用equals
时,它将抛出NullPointerException
。这可以通过以下方式避免
但是在这种情况下,基于流的解决方案并没有什么实际的优势。并行性可能会为 * 真正 * 大的列表带来优势,但不应该随意地在这里或那里添加一些
parallel()
,假设它 * 可能 * 使事情更快。首先,您应该清楚地识别实际的瓶颈。就可读性而言,我更喜欢第一个经典的解决方案,如果你想检查
names.contains(aParticularValue)
的列表,你应该这样做-它读起来像散文,使意图清楚。编辑
contains
方法的另一个优点在评论和其他回答中提到过,在这里可能值得一提:如果names
集合的类型后来被改变了,比如,变成了HashSet
,那么你将免费获得更快的contains
-check(用O(1)代替O(n)),而不需要改变代码的任何其他部分,基于流的解决方案仍然需要迭代 all 个元素,这可能会显著降低性能。js81xvg62#
如果以合理的方式编写
hashCode()
和equals()
,则它们应提供相同的结果。但是性能可能会完全不同,对于列表来说,这并不重要,但是对于HashSet,
contains()
将使用hashCode()
来定位元素,并且它将在恒定时间内完成(最有可能),而对于第二种解决方案,它将在所有项上循环并调用一个函数,因此将在线性时间内完成。如果n为空,实际上并不重要,因为通常
equals()
方法知道null
参数。