Java包含vs anyMatch行为

时间:2016-02-04 11:49:20

标签: java java-stream equality

因此,如果我有Name个对象并且ArrayList类型为Namenames),我想知道我的名字列表是否包含给定的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因为它可以利用懒惰和并行性吗?

2 个答案:

答案 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个参数。