因此,如果我有Name
个对象并且ArrayList
类型为Name
(names
),我想知道我的名字列表是否包含给定的Name
对象(n
),我可以通过两种方式完成:
boolean exists = names.contains(n);
或
boolean exists - names.stream().anyMatch(x -> x.equals(n));
我在考虑这两个是否会表现相同,然后考虑如果n被分配null
会发生什么?
对于contains,据我所知,如果参数为null
,则如果列表包含true
,则返回null
。我将如何实现此anyMatch
- 是否可以使用Objects.equals(x, n)
?
如果可行,那么哪种方法更有效 - 它是anyMatch
因为它可以利用懒惰和并行性吗?
答案 0 :(得分:24)
基于流的版本的问题是如果集合(及其流)包含null
元素,那么谓词将抛出NullPointerException
尝试在此equals
对象上调用null
。
这可以通过
来避免boolean exists = names.stream().anyMatch(x -> Objects.equals(x, n));
但在这种情况下,基于流的解决方案没有实际的优势。并行性可能会为真正的大型列表带来优势,但是不应该随便扔掉一些parallel()
这里和那里假设它可以使事情变得更快。首先,你应该清楚地确定实际的瓶颈。
就可读性而言,我更喜欢这里的第一个经典解决方案。如果你想检查names.contains(aParticularValue)
的列表,你应该这样做 - 它只是读起来像散文并使意图明确。
修改
评论和其他答案中提到了contains
方法的另一个优点,这里可能值得一提:如果names
集合的类型稍后更改,例如,要成为HashSet
,那么您将免费获得更快contains
- 检查(使用O(1)而不是O(n)) - 而无需更改代码的任何其他部分。然后,基于流的解决方案仍然必须迭代所有元素,这可能会显着降低性能。
答案 1 :(得分:2)
如果以合理的方式撰写hashCode()
和equals()
,他们应该提供相同的结果。
但表现可能完全不同。对于列表而言,它并不重要,但对于HashSet contains()
将使用hashCode()
来定位元素,并且它将在恒定时间内完成(最有可能)。使用第二个解决方案时,它将遍历所有项目并调用函数,因此将在线性时间内完成。
如果n为null,实际上并不重要,因为通常equals()
方法都知道null
个参数。