Java 包含 vs anyMatch 行为

Java contains vs anyMatch behaviour

所以如果我有一个 Name 对象和一个类型为 Name (names) 的 ArrayList,我想确定我的名字列表是否包含对于给定的 Name 对象 (n),我可以通过两种方式实现:

boolean exists = names.contains(n);

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

我在考虑这两个行为是否相同,然后考虑如果分配 n 会发生什么情况 null?

对于包含,据我了解,如果参数是 null,那么它 returns true 如果列表包含 null。我将如何实现这个 anyMatch - 是通过使用 Objects.equals(x, n) 吗?

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

基于流的版本的问题是 如果 集合(及其流)包含 null 个元素,则谓词将抛出 NullPointerException 当它试图在此 null 对象上调用 equals 时。

这可以通过

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

但在这种情况下,基于流的解决方案没有实际优势。并行性可能会给 really 大列表带来优势,但不应该随意地在这里和那里扔一些 parallel() 假设它 可能 让事情变得更快。首先,你应该清楚地识别实际的瓶颈。

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

EDIT

contains 方法的另一个优点在评论和其他答案中提到,这里可能值得一提:如果稍后更改 names 集合的类型,因为例如,要成为 HashSet,那么您将免费获得更快的 contains-check(使用 O(1) 而不是 O(n))——无需更改代码的任何其他部分。基于流的解决方案仍然必须遍历 all 元素,这可能会显着降低性能。

如果 hashCode()equals() 写得合理,它们应该提供相同的结果。

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

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