Java 包含与 anyMatch 行为

2022-08-31 20:38:26

因此,如果我有一个对象并且有一个类型(),并且我想确定我的名字列表是否包含给定的对象(),我可以通过两种方式做到这一点:NameArrayListNamenamesNamen

boolean exists = names.contains(n);

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

我正在考虑这两者是否会表现得一样,然后想着如果分配了n会发生什么?null

对于包含,据我所知,如果参数是 ,那么如果列表包含 ,则返回。我将如何实现这一点 - 会通过使用吗?nulltruenullanyMatchObjects.equals(x, n)

如果这就是它的工作原理,那么哪种方法更有效 - 因为它可以利用懒惰和并行性吗?anyMatch


答案 1

基于流的版本的问题在于,如果集合(以及因此其流)包含元素,则谓词在尝试调用此对象时将引发 a。nullNullPointerExceptionequalsnull

这可以通过以下方式避免

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

但是,在这种情况下,基于流的解决方案没有实际优势。并行性可能会为非常大的列表带来优势,但人们不应该随便在这里和那里投入一些,假设它可能会使事情变得更快。首先,您应该清楚地确定实际的瓶颈。parallel()

就可读性而言,我更喜欢这里的第一个经典解决方案。如果你想检查列表是否,你应该这样做 - 它只是读起来像散文,并清楚地表明意图。names.contains(aParticularValue)

编辑

该方法的另一个优点在注释和其他答案中提到,这可能值得在这里提及:如果集合的类型稍后被更改,例如,更改为 ,那么您将免费获得更快的 -check(使用 O(1) 而不是 O(n)) - 而无需更改代码的任何其他部分。然后,基于流的解决方案仍然必须遍历所有元素,并且这可能具有显着较低的性能。containsnamesHashSetcontains


答案 2

如果并且以合理的方式编写,它们应该提供相同的结果。hashCode()equals()

但性能可能完全不同。对于列表来说,这并不重要,但对于HashSet来说,它将用于定位元素,并且它将(最有可能)在恒定时间内完成。而使用第二个解决方案,它将遍历所有项目并调用一个函数,因此将在线性时间内完成。contains()hashCode()

如果 n 为 null,实际上并不重要,因为通常方法都知道参数。equals()null