Реализации коллекций Java (например, HashMaps против HashSet против HashTable ...), какова стоимость выбора неправильной?

В моем коде я по умолчанию использую ArrayList для всех списков, HashMap для всех карт, HashSet для всех наборов.

С практической точки зрения, сколько я теряю в гибкости, масштабируемости, удобочитаемости и производительности, выбирая неправильную реализацию? Когда имеет смысл тратить время на решение использовать один, а не другой?

Я, конечно, вижу очень четкий пример того, почему кто-то будет использовать LinkedList вместо ArrayList при определенных обстоятельствах. Когда кто-то чувствует, что очень важно использовать HashMap, а не TreeMap или HashTable? Как насчет наборов?

Вопросы:

  1. Какова стоимость выбора плохо?
  2. Есть ли у кого-нибудь истории о выборе неправильной реализации и возгорании центра обработки данных?
  3. Есть хорошие правила?
  4. Есть ли какие-то неясные реализации коллекций, без которых вы не можете жить?

Я прочитал:

Я обнаружил, что этот вопрос связан с теоретической точки зрения, но меня больше интересует реальный мир, а не ответ траншей.

3 ответа

Решение

Это очень общий вопрос, но я добавлю пару мыслей.

Если вы программируете для интерфейсов, гибкость не будет иметь большого значения. Например

void foo(List<E> list);

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

Наборы имеют похожую проблему. Если вы хотите сохранить отсортированные коллекции без дубликатов, SortedSet будет более разумным выбором, чем HashSet. В последнем случае вам придется отсортировать весь набор вручную (это вызов Collections.sort()).

<EDIT>

Что касается карт, есть много разных реализаций. У каждого своя цель. Например, есть SortedMap, аналог SortedSet. Затем есть WeakHashMap, который не работает как HashMap, в том смысле, что ключи могут быть удалены сборщиком мусора. Как вы можете себе представить, выбор между HashMap и WeakHashMap не тривиален. Как всегда, зависит от того, что вы хотите реализовать с ними.

</EDIT>

Что касается истории, в моем текущем проекте мы заменили HashSet на SortedSet, потому что это влияло на производительность. Датацентр не загорелся, хотя.

Мои два цента.

Я думаю, что вы можете использовать HashMap, HashSet и ArrayList в качестве основных реализаций. Когда вам нужен отсортированный набор, полезно знать, что TreeSet доступен; аналогично, когда вы делаете рекурсивные вещи, очень удобно иметь LinkedList в вашем заднем кармане. Но запрограммируйте интерфейсы, и тогда вы сможете поменять реализации по мере необходимости. И если одна и та же коллекция требует обработки как (например) как LinkedList, так и ArrayList, нет ничего сложного в создании одного из другого.

Работайте с реализациями по умолчанию, которые вы перечислили. Когда есть проблемы с производительностью, и есть основания полагать, что альтернативная реализация будет лучше, замените ее - и измерьте разницу. Когда вам нужно особое поведение (например, отсортированные наборы), используйте специальные классы.

Этот подход еще не обожг меня.

До тех пор, пока вы следуете хорошей ОО-практике зависимости от абстрактного типа, какое это имеет значение?

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

Другие вопросы по тегам