2010-01-06 3 views
2

Мы получаем эту ошибкуРазличные реализации ArrayList

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() возвращаетнуля. И этот конструктор выглядел безопасным (и работал без исключения) для реализации 1.5.0_09 Sun JDK/JRE, которую мы используем.
Но openJDK, похоже, выпускает для мира unix. Этот код также является частью Windows JRE? И если да, то какая версия?

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

+0

Из интереса, почему вам нужно расширить 'ArrayList'? –

+0

Это просто ярлык для преобразования массивов в типизированные списки. Но я думаю, вы хотели спросить, почему мы реализуем коллекцию с нуля - это наша работа для ИТ-директоров. Я думаю, что я собираюсь заменить это на Arrays.asList() ... – Stroboskop

ответ

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.

+0

Это подтверждает мое подозрение, что наши клиенты изменили нашу установку с помощью более новой JRE. Я еще не думал о проверке с 1.6 JRE. – Stroboskop

+1

Вот источник от 1.5.0_20 JDK: http://pastebin.com/f2710e36c В этой версии конструктор проверяет размер с помощью c.size(), а не c.toArray(). Length –

8

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

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

+0

Что он сказал. +1, за исключением того, что у меня нет голосов на сегодня. –

+0

Не очень полезный ответ. – Timothy

+0

@Carl Smotricz: кто ты на стороне :-)? Повторяются ли комментарии? – bmargulies

1

По J2SE 5.0 API Documentation:

ArrayList общественного ArrayList (Collection с) Создает список, содержащий элементы указанной коллекции, в порядке их возвращенного итератора в коллекции. Экземпляр ArrayList имеет начальную емкость 110% размер указанной коллекции .

Параметры: c - коллекция, элементы которой должны быть размещены в этом списке .

Throws:
NullPointerException - если указанная коллекция является нулевой.

Так

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

бросает NullPointerException если new ArrayCollection<E>(data) является недействительным.

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 имеет эти строки в ArrayList конструктора. Согласно документации этого конструктора: 146 * @throws NullPointerException, если указанная коллекция равна null

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

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

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

Collection.toArray().length метод.

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

В соответствии с J2SE Collection.toArray документации

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

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

Этот метод действует как мост между интерфейсами на основе массивов и наборами данных.

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

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

+0

um ... да. но «новое что-то» - _never_ null. – Stroboskop

+0

Хорошо, если 'new ArrayCollection (data)' не генерирует исключение, а затем ** в соответствии с API Reference 'new ArrayList (новый ArrayCollection (data));' также не должен генерировать исключение. Он инициализирует ArrayList, и если у коллекции есть 0 элементов, то ArrayList также будет содержать 0 элементов. Это означает, что любая истинная реализация не будет генерировать исключение NullPointerException здесь. – JCasso

+0

Да. вот что это такое: различия в реализациях ArrayList, которые могут вызвать исключение. – Stroboskop

1

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

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

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

Смежные вопросы