HashMap или TreeMap или LinkedHashMap какой из них быстрее перебирать?

у меня есть Map который заполняется во время запуска приложения. Он не изменяется позже во время выполнения приложения. Позже эта карта используется только для итерации всех элементов в ней. Какая конкретная реализация Map должен ли я выбрать? HashMap или TreeMap или LinkedHashMap ?
обновление
Порядок вставки не имеет значения. Единственное, что имеет значение, - это быстрая итерация всех элементов (скажем, 6000 элементов).

6 ответов


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

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

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


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

вы можете использовать ImmutableMap или UnmodifiableMap если карта не изменится после ее инициализации


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


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

// Which map you use only chooses the order of the list.
Map<Key,Value> map = new HashMap<>();
// The list to iterate for maximum speed.
List<Map.Entry<Key,Value>> list = new ArrayList<>(map.entrySet());

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

Примечание изменилась с LinkedList to ArrayList на Марко предложение.


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

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


Карте.forEach (BiConsumer) почти всегда быстрее, чем итераторы, иногда с большим отрывом. Если вы суммировали значения, например:

public class TestForStackOverflow {
    int sum = 0;

    // Or whatever Map you are using
    Map<Object, Integer> map = new HashMap();

    static class C implements BiConsumer<Object, Integer> {
        int sum = 0;

        @Override
        public void accept(Object k, Integer v) {
            sum += v;
        }
    }

    public int getSum(Map map) {
        C c = new C();
        map.forEach(c);
        return c.sum;
    }

    public int getSum2(Map map) {
        map.forEach((k, v) -> sum += v);
        return sum;
    }
}