Question

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.

Was it helpful?

Solution

I don't think you specified exactly which JRE version/vendor you are using, but here is the source for the constructor in question for Sun JDK 1.6.0_17 (if you aren't already aware, the source for most classes in the java namespace ships with the 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);
}

(the comment is the author's, not mine)

This should pretty clearly show the potential cause of a NPE in this constructor: if c is null or (in your case) if c.toArray() returns null.

OTHER TIPS

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.

The List#toArray method should never return null. Your implementation of ArrayCollection may have overriden the toArray methods and may be returning null for empty collections instead of a new empty array.

And yes, it is possible that different JRE's behave differently. Some may tolerate null instead of an array while others don't.

I'd fire up my Java decompiler and have a look at the actual implementation of this ArrayList constructor.

According to J2SE 5.0 API Documentation:

ArrayList public ArrayList(Collection c) Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator. The ArrayList instance has an initial capacity of 110% the size of the specified collection.

Parameters: c - the collection whose elements are to be placed into this list.

Throws:
NullPointerException - if the specified collection is null.

So

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

throws NullPointerException if new ArrayCollection<E>(data) is null.

Edit:

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 has these lines in ArrayList constructor. According to the documentation of this constructor: 146 * @throws NullPointerException if the specified collection is null

It should only throw an exception if collection is null.

Here these lines:

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

Collection.toArray().length method is called.

In your implementation Collection.toArray() is null so it throws a NullPointerException.

According to J2SE Collection.toArray documentation

toArray Object[] toArray() Returns an array containing all of the elements in this collection. If the collection makes any guarantees as to what order its elements are returned by its iterator, this method must return the elements in the same order.

The returned array will be "safe" in that no references to it are maintained by this collection. (In other words, this method must allocate a new array even if this collection is backed by an array). The caller is thus free to modify the returned array.

This method acts as bridge between array-based and collection-based APIs.

Returns: an array containing all of the elements in this collection

So it should not return null. It should return an empty array. So .length will return 0 and there will be no problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top