为什么 list.contains(null) 抛出空指针异常?

Why list.contains(null) throwing null pointer exception?

我有 List<Long> countriesList,其中包含 Long 个国家 ID 值。

现在我正在使用 streams.

迭代一些 List<UserRequests> 列表
userRequests.stream().
    forEach(userRequest->
    {
        UserData=userRepository.findById(userRequest.getId()); //fine
        if (CollectionUtils.isNotEmpty(countriesList) && countriesList.contains(userRequest.getCountryId()))//getting NPE here
        {
            //do some operation
        }
    });

我尝试通过评估单个语句来进行调试。 我确定 countriesList 有一些数据 第一部分 CollectionUtils.isNotEmpty(countriesList) 返回 trueuserRequest 也不为空,但 userRequest.getCountryId() 为空。 当我评估 countriesList.contains(userRequest.getCountryId()) 时,我在这里得到 Null pointer exception。为什么不 false ? 我很困惑我做错了什么。 默认 list.contains(null) 行为只是这样还是因为我在 stream()?

中调用它

为了简单起见,我创建了简单列表并与 null 进行了比较。

class Test {
    public static void main(String[] args) {
        List<Long> longList = List.of(1L, 2L, 3L);
        System.out.println("Comparing long list with null::" + longList.contains(null));
    }
}

这是我遇到的异常:

Exception in thread "main" java.lang.NullPointerException
    at java.base/java.util.Objects.requireNonNull(Objects.java:222)
    at java.base/java.util.ImmutableCollections$AbstractImmutableList.indexOf(ImmutableCollections.java:166)
    at java.base/java.util.ImmutableCollections$AbstractImmutableList.contains(ImmutableCollections.java:197)
    at com.test.Test.main(Test.java:26)

但如果我这样做:

    List<Long> longList = new ArrayList<>();
    longList.add(1L);
    System.out.println("Comparing long list with null::" + longList.contains(null));

为什么要打印 false?为什么这里没有 NullPointerException

来自 java.util.List 的 API 文档:

Some list implementations have restrictions on the elements that they may contain. For example, some implementations prohibit null elements, and some have restrictions on the types of their elements. Attempting to add an ineligible element throws an unchecked exception, typically NullPointerException or ClassCastException. Attempting to query the presence of an ineligible element may throw an exception, or it may simply return false; some implementations will exhibit the former behavior and some will exhibit the latter. More generally, attempting an operation on an ineligible element whose completion would not result in the insertion of an ineligible element into the list may throw an exception or it may succeed, at the option of the implementation. Such exceptions are marked as "optional" in the specification for this interface.

boolean contains(Object o)

Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that Objects.equals(o, e).

Specified by:

contains in interface Collection

Parameters:

o - element whose presence in this list is to be tested

Returns:

true if this list contains the specified element

Throws:

ClassCastException - if the type of the specified element is incompatible with this list (optional)

NullPointerException - if the specified element is null and this list does not permit null elements (optional)

您的 countriesList 似乎是不接受 null 元素的列表类型,例如 List.ofList.copyOf[=18 生成的元素=]

Why list.contains(null) throwing null pointer exception?

因为这是规范所说的可能发生的情况。

List.of(...)案的具体推理如下:

  1. List.of 方法是 specified as producing unmodifiable lists

  2. 不可修改列表 specified 不允许 null 元素:

    "They disallow null elements. Attempts to create them with null elements result in NullPointerException."

  3. List.containsjavadoc 状态:

    "Throws: NullPointerException - if the specified element is null and this list does not permit null elements.

换句话说,您看到的是指定的行为...而不是不正确或反复无常的实施的结果。

对于搜索 countryList 的情况...这将取决于实际 List 实施 class。但是 List 规范中对 contains 有一个明确的预期,如果您尝试搜索 null一些 种类的列表可能会抛出 NPE .

(这是否是一个“糟糕的设计选择”是一个见仁见智的问题。但这没有实际意义。List 设计选择是很久以前做出的,并且正在改变它们现在会破坏性太大而无法考虑。此外,我怀疑您能否说服当前的 Java 设计团队相信 null 集合类型中的值是个好主意。)