【问题标题】:Why list.contains(null) throwing null pointer exception?为什么 list.contains(null) 抛出空指针异常?
【发布时间】:2022-01-24 18:34:22
【问题描述】:

我有 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 设计选择不当的结果,具体取决于您的版本。)
  • @louis-wasserman 更新了问题以包括异常堆栈跟踪和我当前使用的 jdk 版本是jdk-14.0.2
  • 删除了 [java-8] 标签,因为 JDK 14 显然不是 Java 8。

标签: java exception collections nullpointerexception


【解决方案1】:

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

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

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

  1. List.of 方法是 specified 生成 unmodifiable lists

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

    “它们不允许空元素。尝试使用null 元素创建它们会导致NullPointerException。”

  3. List.containsjavadoc 声明:

    “抛出:NullPointerException - 如果指定的元素是 null 并且此列表不允许 null 元素。

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

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

(这是否是“糟糕的设计选择”是一个见仁见智的问题。但这没有实际意义。List 设计选择是很久以前做出的,现在改变它们会造成太大的破坏去思考。此外,我怀疑你是否会让当前的 Java 设计团队相信集合类型中的 null 值是个好主意。)

【讨论】:

    【解决方案2】:

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

    一些列表实现对它们可能包含的元素有限制。例如,一些实现禁止空元素,而一些实现对其元素的类型有限制。尝试添加不合格的元素会引发未经检查的异常,通常是 NullPointerException 或 ClassCastException。尝试查询不合格元素的存在可能会引发异常,或者它可能只是返回 false;一些实现会表现出前一种行为,而另一些会表现出后者。更一般地,尝试对不合格元素进行操作,其完成不会导致将不合格元素插入列表中,这可能会引发异常,也可能会成功,这取决于实现的选择。此类异常在此接口的规范中被标记为“可选”。

    布尔包含(对象o)

    如果此列表包含指定的元素,则返回 true。更正式地说,当且仅当此列表包含至少一个元素 e 满足 Objects.equals(o, e) 时才返回 true。

    指定者:

    包含在接口集合中

    参数:

    o - 要测试其是否存在于此列表中的元素

    返回:

    如果此列表包含指定元素则为真

    投掷:

    ClassCastException - 如果指定元素的类型与此列表不兼容(可选)

    NullPointerException - 如果指定元素为 null 并且此列表不允许 null 元素(可选)

    您的countriesList 似乎是不接受null 元素的List 类型,例如List.ofList.copyOf 产生的元素

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-25
      • 2015-09-19
      • 2013-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-22
      相关资源
      最近更新 更多