Реализации коллекций Java (например, HashMaps против HashSet против HashTable ...), какова стоимость выбора неправильной?
В моем коде я по умолчанию использую ArrayList для всех списков, HashMap для всех карт, HashSet для всех наборов.
С практической точки зрения, сколько я теряю в гибкости, масштабируемости, удобочитаемости и производительности, выбирая неправильную реализацию? Когда имеет смысл тратить время на решение использовать один, а не другой?
Я, конечно, вижу очень четкий пример того, почему кто-то будет использовать LinkedList вместо ArrayList при определенных обстоятельствах. Когда кто-то чувствует, что очень важно использовать HashMap, а не TreeMap или HashTable? Как насчет наборов?
Вопросы:
- Какова стоимость выбора плохо?
- Есть ли у кого-нибудь истории о выборе неправильной реализации и возгорании центра обработки данных?
- Есть хорошие правила?
- Есть ли какие-то неясные реализации коллекций, без которых вы не можете жить?
Я прочитал:
- http://java.sun.com/j2se/1.4.2/docs/api/java/util/TreeMap.html
- http://java.sun.com/j2se/1.4.2/docs/api/java/util/HashMap.html
- Java: ArrayList для списка, HashMap для карты и HashSet для набора? так далее...
Я обнаружил, что этот вопрос связан с теоретической точки зрения, но меня больше интересует реальный мир, а не ответ траншей.
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
все работает как и прежде, только с разными характеристиками производительности.