Почему бы не всегда использовать ArrayLists в Java вместо простых старых массивов? - PullRequest
7 голосов
/ 04 апреля 2009

Быстрый вопрос: почему бы ВСЕГДА не использовать ArrayLists в Java? Они, по-видимому, имеют равную скорость доступа, как массивы, в дополнение к дополнительным полезным функциям. Я понимаю ограничение, заключающееся в том, что он не может содержать примитивы, но это легко можно уменьшить, используя обертки.

Ответы [ 5 ]

12 голосов
/ 04 апреля 2009

Множество проектов просто используют ArrayList или HashMap или что-то еще, чтобы удовлетворить все их потребности в сборе. Тем не менее, позвольте мне сделать одно предупреждение. Всякий раз, когда вы создаете классы и используете их в своем коде, по возможности обращайтесь к интерфейсам, которые они реализуют, а не к конкретным классам, которые вы используете для их реализации.

Например, вместо этого:

ArrayList insuranceClaims = new ArrayList();

сделать это:

List insuranceClaims = new ArrayList();

или даже:

Collection insuranceClaims = new ArrayList();

Если остальная часть вашего кода знает его только по интерфейсу, который он реализует (List или Collection), то замена его на другую реализацию станет намного проще в будущем, если вы обнаружите, что вам нужна другая. Я видел, что это случилось всего месяц назад, когда мне нужно было поменять обычный HashMap на реализацию, которая возвращала бы мне элементы в том же порядке, в котором я их поместил, когда пришло время перебирать их все. К счастью, именно такая вещь была доступна в коллекциях Jakarta Commons, и я просто заменил A на B, изменив код только на одну строку, потому что оба реализовали Map.

9 голосов
/ 04 апреля 2009

Если вам нужна коллекция примитивов, тогда массив может быть лучшим инструментом для работы. Бокс - это сравнительно дорогая операция. Для коллекции (не включая карты) примитивов, которая будет использоваться в качестве примитивов, я почти всегда использую массив, чтобы избежать повторяющихся упаковок и распаковок.

Однако я редко беспокоюсь о разнице в производительности между массивом и ArrayList. Если List предоставит лучший, более чистый и более понятный код, то я всегда буду использовать List (или Collection или Set и т. Д., В зависимости от ситуации, но ваш вопрос был о ArrayList), если нет это убедительная причина не делать этого. Производительность - редко - это веская причина.

Использование Collection s почти всегда приводит к лучшему коду, отчасти потому, что массивы не очень хорошо работают с дженериками, как уже указывал Йоханнес Вайс в комментарии, но также и по многим другим причинам:

  • Коллекции имеют очень богатый API и большое разнообразие реализаций, которые можно (в большинстве случаев) легко заменять друг на друга
  • Коллекция может быть легко преобразована в массив, если иногда полезно использование версии массива
  • Многие коллекции растут изящнее, чем массив, что может быть проблемой производительности
  • Коллекции очень хорошо работают с дженериками, массивы довольно плохо
  • Как указывал TofuBeer, ковариация массива странная и может действовать неэкспонированными способами, в которых не будет действовать ни один объект. Коллекции обрабатывают ковариацию ожидаемым образом.
  • Размеры массивов должны быть вручную определены для их задачи, и если массив не заполнен, вам нужно следить за этим самостоятельно. Если нужно изменить размер массива, вы должны сделать это самостоятельно.

Все это вместе, я редко использую массивы и лишь немного чаще использую ArrayList. Однако я очень часто использую List (или просто Collection или Set). Чаще всего я использую массивы, когда хранимый элемент является примитивом, который будет вставлен, доступен и использован как примитив. Если бокс и распаковка становятся настолько быстрыми, что это становится тривиальным соображением, я могу вернуться к этому решению, но удобнее работать с чем-то, хранить его в той форме, в которой на него всегда ссылаются. (То есть вместо целого числа int).

5 голосов
/ 04 апреля 2009

Производительность не должна быть вашей главной заботой.

По возможности используйте интерфейс List, выберите конкретную реализацию на основе фактических требований (ArrayList для произвольного доступа, LinkedList для структурных изменений, ...).

Вы должны быть обеспокоены производительностью.

Используйте массивы, System.arraycopy, java.util.Arrays и другие низкоуровневые вещи, чтобы выжать каждую последнюю потерю производительности.

4 голосов
/ 04 апреля 2009

Это случай преждевременной неоптимизации :-). Вы никогда не должны делать что-то, потому что вы думаете, что это будет лучше / быстрее / сделает вас счастливее.

ArrayList имеет дополнительные накладные расходы, если вам не нужны дополнительные функции ArrayList, тогда использовать ArrayList расточительно.

Также для некоторых вещей, которые вы можете делать со списком, есть класс Arrays, что означает, что ArrayList предоставил больше функциональных возможностей, чем Arrays, и это менее верно. Теперь их использование может быть медленнее, чем использование ArrayList, но для уверенности его необходимо профилировать.

Вы никогда не должны пытаться сделать что-то быстрее, не будучи уверенным, что это медленно с самого начала ... что подразумевает, что вы должны продолжать и использовать ArrayList, пока не обнаружите, что они являются проблемой, и замедлить работу программы. Однако в этом также должен быть здравый смысл - ArrayList накладные расходы, накладные расходы будут небольшими, но накапливаются. Это не будет легко заметить в профилировщике, так как все это немного над головой и немного над головой. Так что здравый смысл сказал бы: если вам не нужны функции ArrayList, вы не должны использовать его, если вы не хотите умереть тысячами сокращений (с точки зрения производительности).

Для внутреннего кода, если вы обнаружите, что вам нужно перейти с массивов на ArrayList, вероятность в большинстве случаев довольно проста ([i] становится get (i), что будет 99% изменений).

Если вы используете просмотр for-each (for (value: items) {}), то для этого также нет кода, который можно изменить.

Также, продолжая то, что вы сказали:

1) одинаковая скорость доступа, в зависимости от вашей среды. Например, виртуальная машина Android не имеет встроенных методов (насколько я знаю, это просто прямой интерпретатор), поэтому доступ к ней будет намного медленнее. Существуют и другие операции с ArrayList, которые могут вызывать замедления, в зависимости от того, что вы делаете, независимо от виртуальной машины (которая может быть быстрее с прямым массивом, опять же вам придется профилировать или проверять источник, чтобы быть уверенным).

2) Обертки увеличивают объем используемой памяти.

Вы не должны беспокоиться о скорости / памяти, прежде чем что-то профилировать, с другой стороны, вы не должны выбирать то, что вы знаете, как более медленный вариант, если у вас нет веских причин для этого.

2 голосов
/ 04 апреля 2009

Ну, не всегда слепо использовать что-то, что не подходит для работы. Всегда начинайте с использования списков, выберите ArrayList в качестве своей реализации. Это более ОО подход. Если вы не знаете, что вам конкретно нужен массив, вы обнаружите, что в долгосрочной перспективе вам не будет лучше привязываться к конкретной реализации List. Сначала запустите, оптимизируйте позже.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...