Различные реализации ArrayList - PullRequest
2 голосов
/ 06 января 2010

Мы получаем эту ошибку

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

, где ExtendedArrayList: 38 равно

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

Вкратце: конструктор ArrayList иногда кажется подавленным реализацией нашей домашней коллекции ArrayCollection.

Мне не удалось воспроизвести его на моем компьютере даже с той же версией, которая была распространена среди наших клиентов.

Но я не уверен на 100%, что они используют JRE, который мы включили. Итак, я гуглил некоторый исходный код ArrayList.java и нашел openJDK 6b17, который имеет этот

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);
}

Это имело бы смысл, потому что если нет данных, наша ArrayCollection.toArray () возвращает null И этот конструктор выглядел безопасным (и работал без исключения) для используемой нами реализации JDK / JRE 1.5.0_09.
Но openJDK, похоже, выпускается только для мира Unix. Этот код также является частью Windows JRE? И если да, то какая версия?

Примечание: я знаю, что мы должны исправить наши классы, но я хочу убедиться, что я понимаю причину исключения NullPointerException.

Ответы [ 4 ]

8 голосов
/ 06 января 2010

Почему вы думаете, что законно возвращать нуль, а не массив нулевой длины?

Javadoc для List не допускает этого. Таким образом, причина в том, что все другие JRE делают то же самое предположение. Опубликованные источники реализации Sun на моем Mac, безусловно, делают это предположение.

1 голос
/ 06 января 2010

Я не думаю, что вы точно указали, какую версию / поставщика 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 равно нулю или (в вашем случае), если c.toArray() возвращает ноль.

1 голос
/ 06 января 2010

Метод List # toArray никогда не должен возвращать ноль. Ваша реализация ArrayCollection может переопределить методы toArray и может возвращать ноль для пустых коллекций вместо нового пустого массива.

И да, возможно, что разные JRE ведут себя по-разному. Некоторые могут терпеть ноль вместо массива, в то время как другие - нет.

Я бы запустил мой Java-декомпилятор и взглянул бы на фактическую реализацию этого конструктора ArrayList.

1 голос
/ 06 января 2010

Согласно документации API J2SE 5.0 :

ArrayList public ArrayList (Коллекция 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, если указанная коллекция пуста

Он должен выдавать исключение, только если коллекция равна нулю.

Вот эти строки:

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

Collection.toArray().length метод вызывается.

В вашей реализации Collection.toArray() имеет значение null, поэтому он генерирует исключение NullPointerException.

Согласно документации J2SE Collection.toArray

toArray Object [] toArray () Возвращает массив, содержащий все элементы в этой коллекции. Если коллекция дает какие-либо гарантии относительно того, какой заказ его элементы возвращаются его итератор, этот метод должен возвращать элементы в том же порядке.

Возвращенный массив будет "безопасным" в что нет ссылок на это поддерживается этой коллекцией. (В другими словами, этот метод должен выделить новый массив, даже если эта коллекция поддерживается массивом). Звонящий Таким образом, свободно изменять возвращаемый массив.

Этот метод действует как мост между API на основе массива и коллекции.

Возвращает: массив, содержащий все элементы в этой коллекции

Так что он не должен возвращать ноль. Он должен вернуть пустой массив. Таким образом, .length вернет 0 и проблем не будет.

...