Подтвердить что ты не робот

Какую реализацию Map <K, V> следует использовать, если моя карта должна быть маленькой, чем быстрее?

Я обычно использую HashMap в своих программах, так как я знаю, что он обычно наиболее эффективен (если он правильно используется) и может легко справляться с большими картами. Я знаю о EnumMap, который очень полезен для ключей перечисления, но часто я генерирую небольшую карту, которая никогда не будет очень большой, скорее всего, будет отброшена довольно скоро и не будет иметь проблем с concurrency.

Является ли HashMap<K,V> слишком сложным для этих небольших, локальных и временных применений? Есть ли другая, простая реализация, которую я могу использовать в этих случаях?

Я думаю, что я ищу реализацию Map, которая аналогична ArrayList для List. Он существует?


Добавлено позже после ответов:

Вот сценарий, где медленная, но очень простая реализация может быть лучше - когда у меня есть много, многие из этих Map s. Предположим, например, что у меня есть миллион или около того этих маленьких маленьких карт, каждый из которых содержит несколько (обычно менее трех) записей. У меня низкая базовая ставка - возможно, я на самом деле не ссылаюсь на них, прежде чем их отбрасывают большую часть времени. Это все еще так, что HashMap - лучший выбор для них?

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

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


Добавлено намного позже после некоторого раздумья:

Я решил скомпоновать собственный SmallMap. Легко сделать один с AbstractMap. Я также добавил несколько конструкторов, чтобы a SmallMap можно было построить из существующего Map.

По пути мне пришлось решить, как представить Entry и реализовать SmallSet для метода entrySet.

Я многому научился при кодировании (и модульном тестировании этого) и хочу поделиться этим, если кто-то еще захочет этого. Он находится на github здесь.

4b9b3361

Ответ 1

В Java нет стандартной небольшой реализации Map. HashMap - одна из лучших и наиболее гибких реализаций Map, и ее трудно превзойти. Однако в очень маленькой области требований - где использование кучи и скорость строительства имеют первостепенное значение - можно сделать лучше.

Я реализовал SmallCollections в GitHub, чтобы продемонстрировать, как это можно сделать. Мне бы хотелось, чтобы некоторые комментарии о том, удалось ли мне преуспеть. Я отнюдь не уверен, что у меня есть.

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

Вопрос здесь послужил своей цели, и именно поэтому я сам "ответил сам".

Ответ 2

Я думаю, что это преждевременная оптимизация. У вас проблемы с памятью? Проблемы с производительностью при создании слишком большого количества карт? Если нет, я думаю, что HashMap в порядке.

Кроме того, глядя на API, я не вижу ничего проще, чем HashMap.

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

Ответ 3

A HashMap - это, пожалуй, самая легкая и простая коллекция.

Иногда более эффективным решением является использование POJO. например если ваши ключи являются именами полей и/или ваши значения являются примитивами.

Ответ 4

HashMap - хороший выбор, потому что он предлагает средний случай O(1) puts and gets. Он не гарантирует упорядочение, как, например, SortedMap-реализации (т.е. TreeMap O(log n) puts and gets), но если у вас нет требований к порядку, то лучше HashMap.

Ответ 5

Я согласен с @hvgotcodes в том, что это преждевременная оптимизация, но все же хорошо знать все инструменты в панели инструментов.

Если вы делаете много итераций над тем, что находится на карте, LinkedHashMap обычно намного быстрее, чем HashMap, если у вас много потоков, работающих с Map одновременно, ConcurrentHashMap часто является лучший выбор. Я бы не стал беспокоиться о том, что реализация карты неэффективна для небольших наборов данных. Как правило, наоборот, неправильно построенная карта легко становится неэффективной с большими объемами данных, если у вас плохие хеш-значения или что-то заставляет ее иметь слишком мало ведер для ее загрузки.

Тогда, конечно, есть случаи, когда HashMap вообще не имеет смысла, например, если у вас есть три значения, которые вы всегда будете индексировать с помощью клавиш 0, 1 и 2, но я предполагаю, что вы понимаете, что: -)

Ответ 6

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

Что касается фрагментации кучи и траты GC-цикла, и многое другое, реализация Map может быть очень большой; все это возвращается к тому, как вы его устанавливаете. Поймите, что речь идет не о реализации Java, а о том, что общий (как, например, не может принимать что-либо о значениях ключа, таких как EnumMap) hashtables (not HashTable s), является наилучшим вариантом реализации структуры карты.

Ответ 7

Android имеет ArrayMap с целью сведения к минимуму памяти. Помимо того, что он находится в ядре, он находится в библиотеке поддержки v4, которая, теоретически, должна быть в состоянии скомпилировать для Oracle или OpenJDK JRE. Вот ссылка на источник ArrayMap в вилке библиотеки поддержки v4 на github.

Ответ 8

Существует альтернатива AirConcurrentMap, которая обладает большей эффективностью памяти выше 1K записей, чем любая другая карта, которую я нашел, и быстрее, чем ConcurrentSkipListMap для операций на основе ключей и быстрее, чем любая карта для итераций, и имеет внутренний пул потоков для параллельное сканирование. Это упорядоченная, то есть NavigableMap и ConcurrentMap. Он является бесплатным для некоммерческого использования без источника и коммерчески лицензируется с источником или без него. См. Catbay.com для графиков. Полное раскрытие: я автор.

AirConcurrentMap соответствует стандартам, поэтому он совместим с плагинами везде, даже для обычной Карты.

Итераторы уже очень быстрые, особенно за 1K Записи. При более высокоскоростном сканировании используется модель "посетитель" с обратным вызовом с одним посещением (k, v), который достигает скорости параллельных потоков Java 8. Параллельное сканирование AirConcurrentMap превышает параллельные потоки Java 8 примерно на 4 раза. Посетитель добавляет методы split() и merge() к однопоточному посетителю, которые напоминают карту map/reduce:

static class ThreadedSummingVisitor<K> extends ThreadedMapVisitor<K, Long> {
    private long sum;
    // This is idiomatic
    long getSum(VisitableMap<K, Long> map) {
        sum = 0;
        map.getVisitable().visit(this);
        return sum;
    }

    @Override
    public void visit(Object k, Long v) {
        sum += ((Long)v).longValue();
    }

    @Override
    public ThreadedMapVisitor<K, Long> split() {
        return new ThreadedSummingVisitor<K>();
    }

    @Override
    public void merge(ThreadedMapVisitor<K, Long> visitor) {
        sum += ((ThreadedSummingVisitor<K>)visitor).sum;
    }
}
...
// The threaded summer can be re-used in one line now.
long sum = new ThreadedSummingVisitor().getSum((VisitableMap)map);