Java: ArrayList для списка, HashMap для карты и HashSet для набора? - PullRequest
5 голосов
/ 22 мая 2009

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

Иногда я создаю ArrayList с начальной емкостью, превышающей значение по умолчанию, равное 10, и HashMap с количеством блоков по умолчанию, превышающим 16, но я обычно (особенно для бизнес-CRUD) никогда не думаю, что думаю: «Хм ... использовать LinkedList вместо ArrayList, если я просто собираюсь вставить и перебрать весь список? "

Мне просто интересно, что все остальные здесь используют (и почему) и какой тип приложений они разрабатывают.

Ответы [ 10 ]

10 голосов
/ 22 мая 2009

Это определенно мой вариант по умолчанию, хотя часто LinkedList фактически является лучшим выбором для списков, поскольку подавляющее большинство списков, похоже, просто итерируют по порядку или в любом случае преобразуются в массив через Arrays.asList. *

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

Я всегда печатаю параметры и переменные как «Коллекция», «Карта» и «Список», если только у меня нет особой причины ссылаться на подтип, так как переключение - это одна строка кода, когда вам это нужно.

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

3 голосов
/ 22 мая 2009

Для некоторых видов списков (например, слушателей) имеет смысл использовать CopyOnWriteArrayList вместо обычного ArrayList . Почти для всего остального упомянутые базовые реализации достаточны.

2 голосов
/ 22 мая 2009

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

Map<String, LongObjectClasName> map = CollectionUtils.newMap();

instead of 

Map<String, LongObjectClasName> map = new HashMap<String, LongObjectClasName>();


public class CollectionUtils {
.....

public <T> List<T> newList() {
        return new ArrayList<T>();
    }

    public <T> List<T> newList(int initialCapacity) {
        return new ArrayList<T>(initialCapacity);
    }

    public <T> List<T> newSynchronizedList() {
        return new Vector<T>();
    }

    public <T> List<T> newConcurrentList() {
        return new CopyOnWriteArrayList<T>();
    }

    public <T> List<T> newSynchronizedList(int initialCapacity) {
        return new Vector<T>(initialCapacity);
    }

...
}
2 голосов
/ 22 мая 2009

Да, я использую их по умолчанию. У меня, как правило, есть правило, согласно которому в методах открытого класса я всегда возвращаю тип интерфейса (т. Е. Map, Set, List и т. Д.), Поскольку другим классам (обычно) не нужно знать, что представляет собой конкретный конкретный класс. Внутри методов класса я буду использовать конкретный тип, только если мне нужен доступ к любым дополнительным методам, которые у него могут быть (или если это облегчает понимание кода), в противном случае используется интерфейс.

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

1 голос
/ 22 мая 2009

Если вы используете LinkedList для очереди, вы можете вместо этого использовать интерфейс Deque и реализующий класс ArrayDeque (представленный в Java 6). Чтобы процитировать Javadoc для ArrayDeque:

Этот класс, вероятно, будет быстрее, чем Стек при использовании в качестве стека и быстрее чем LinkedList при использовании в качестве очереди.

1 голос
/ 22 мая 2009

У меня нет "default", хотя я полагаю, что чаще использую реализации, перечисленные в вопросе. Я думаю о том, что подходит для какой-то конкретной проблемы, над которой я работаю, и использую ее. Я не просто слепо по умолчанию использую ArrayList, я потратил 30 секунд на мысли «хорошо, я собираюсь сделать много итераций и удалять элементы в середине этого списка, поэтому я должен используйте LinkedList ".

И я почти всегда использую тип интерфейса для справки, а не для реализации. Помните, что List - не единственный интерфейс, который реализует LinkedList. Я вижу это много:

LinkedList<Item> queue = new LinkedList<Item>();

когда то, что имел в виду программист было:

Queue<Item> queue = new LinkedList<Item>();

Я также использую интерфейс Iterable изрядное количество.

1 голос
/ 22 мая 2009

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

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

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

0 голосов
/ 04 июня 2009

Я тоже обычно использую ArrayList, но я буду использовать TreeSet или HashSet в зависимости от обстоятельств. Однако при написании тестов часто используются Arrays.asList и Collections.singletonList. В основном я писал код для локального потока, но я также мог видеть использование различных параллельных классов.

Также были случаи, когда я использовал ArrayList, когда я действительно хотел LinkedHashSet (до того, как он стал доступен).

0 голосов
/ 22 мая 2009

Использование типа интерфейса (List, Map) вместо типа реализации (ArrayList, HashMap) не имеет значения в методах - это главным образом важно в открытых API, то есть сигнатуры методов (и «публичные» не обязательно означают «предназначенные для быть опубликованным вне вашей команды).

Когда метод принимает ArrayList в качестве параметра, и у вас есть что-то еще, вы облажались и должны бессмысленно копировать ваши данные. Если тип параметра List, вызывающие абоненты гораздо более гибкие и могут, например, используйте Collections.EMPTY_LIST или Collections.singletonList().

0 голосов
/ 22 мая 2009

Я склонен использовать один из * классов очередей для очередей. Однако LinkedList - хороший выбор, если вам не нужна безопасность потоков.

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