2

We're getting this error

java.lang.NullPointerException
    at java.util.ArrayList.<init>(Unknown Source)
    at de.mystuff.ExtendedArrayList.<init>(ExtendedArrayList.java:38)

where ExtendedArrayList:38 is

new ArrayList(new ArrayCollection<E>(data));

In short: the ArrayList constructor sometimes seems to choke on our home grown Collection implementation ArrayCollection.

I was unable to reproduce it on my computer even with the exact same version that was distributed to our customers.

But i'm not 100% sure that they are using the JRE we included. So, i googled for some ArrayList.java source code and found openJDK 6b17 which has this

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, size, Object[].class);
}

That would make sense, because if there's no data our ArrayCollection.toArray() returns null. And this constructor looked safe (and worked without exception) for the 1.5.0_09 Sun JDK/JRE implementation we are using.
But openJDK only seems to release for the unix world. Is this code also part of a Windows JRE? And if so, which version?

NB: I know that we have to fix our classes, but i want to make sure i understand the cause of the NullPointerException.

4

4 回答 4

7

Why do you think that it's legitimate to return null rather than returning a zero-length array?

The javadoc for List does not allow for this. So, the cause is that all the other JRE's make the same assumption. The Sun implementation's published sources on my Mac certainly make that assumption.

于 2010-01-06T12:16:27.497 回答
1

我认为您没有准确指定您使用的 JRE 版本/供应商,但这里是 Sun JDK 1.6.0_17 的相关构造函数的源代码(如果您还不知道,java命名空间中大多数类的源代码随 JDK 一起提供):

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    size = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
         elementData = Arrays.copyOf(elementData, size, Object[].class);
}

(评论是作者的,不是我的)

这应该非常清楚地显示此构造函数中 NPE 的潜在原因:如果c为 null 或(在您的情况下)如果c.toArray()返回 null。

于 2010-01-06T13:05:50.350 回答
1

List#toArray 方法永远不应返回 null。您的 ArrayCollection 实现可能已经覆盖了 toArray 方法,并且可能为空集合返回 null 而不是新的空数组。

是的,不同的 JRE 的行为可能不同。有些人可能会容忍 null 而不是数组,而其他人则不会。

我将启动我的Java 反编译器并查看此 ArrayList 构造函数的实际实现。

于 2010-01-06T12:59:19.987 回答
1

根据J2SE 5.0 API 文档

ArrayList public ArrayList(Collection c) 按照集合的迭代器返回的顺序构造一个包含指定集合元素的列表。ArrayList 实例的初始容量为指定集合大小的 110%。

参数: c - 将其元素放入此列表的集合。

抛出:
NullPointerException - 如果指定的集合为空。

所以

new ArrayList(new ArrayCollection<E>(data));

NullPointerException如果new ArrayCollection<E>(data)为空则抛出。

编辑:

140     /**
141      * Constructs a list containing the elements of the specified
142      * collection, in the order they are returned by the collection's
143      * iterator.
144      *
145      * @param c the collection whose elements are to be placed into this list
146      * @throws NullPointerException if the specified collection is null
147      */
148     public ArrayList(Collection<? extends E> c) {
149     elementData = c.toArray();
150     size = elementData.length;
151     // c.toArray might (incorrectly) not return Object[] (see 6260652)
152     if (elementData.getClass() != Object[].class)
153         elementData = Arrays.copyOf(elementData, size, Object[].class);
154     }

OpenJDK 在 ArrayList 构造函数中有这些行。根据这个构造函数的文档: 146 * @throws NullPointerException if the specified collection is null

如果集合为空,它应该只抛出异常。

这里有这些行:

149     elementData = c.toArray();
150     size = elementData.length;

Collection.toArray().length方法被调用。

在您的实现Collection.toArray()中为 null,因此它会引发 NullPointerException。

根据 J2SE Collection.toArray 文档

toArray Object[] toArray() 返回一个包含此集合中所有元素的数组。如果集合对其迭代器返回其元素的顺序做出任何保证,则此方法必须以相同的顺序返回元素。

返回的数组将是“安全的”,因为此集合不维护对它的引用。(换句话说,即使此集合由数组支持,此方法也必须分配一个新数组)。因此,调用者可以自由修改返回的数组。

此方法充当基于数组和基于集合的 API 之间的桥梁。

返回:包含此集合中所有元素的数组

所以它不应该返回null。它应该返回一个空数组。所以 .length 将返回 0 并且不会有问题。

于 2010-01-06T12:32:39.763 回答