У меня есть Map
, который заполняется во время запуска приложения. Он не изменяется позже во время выполнения приложения. Позже эта карта используется только для повторения всех элементов в ней. Какую конкретную реализацию Map
выбрать? HashMap
или TreeMap
или LinkedHashMap
?
UPDATE
Порядок вставки не имеет значения. Единственное, что имеет значение, это быстрая итерация всех элементов (скажем, 6000 элементов).
HashMap или TreeMap или LinkedHashMap, который быстрее итерации?
Ответ 1
Ни один из других ответов здесь не учитывает влияние кэша процессора, которое может быть огромным при итерации.
Один из способов улучшить это - использовать только один массив чередующихся ключей и значений (клавиши с четными индексами, значения на нечетных). Это будет тесно группировать эти элементы данных и максимально использовать кеш, по крайней мере, для ссылок.
Но истинное, критическое улучшение было бы достигнуто, если бы вы могли избежать создания объектов, которые хранят ваши данные, и использовать только массивы примитивных значений. Это, естественно, сильно зависит от вашего варианта использования.
Ответ 2
HashMap
будет, как правило, самым быстрым, так как он обладает наилучшим поведением кэша (HashMap
выполняет итерацию непосредственно над базовым массивом, тогда как TreeMap
и LinkedHashMap
выполняет итерацию по связанным структурам данных).
Вы можете использовать ImmutableMap или UnmodifiableMap, если карта не изменится после ее инициализации
Ответ 3
Если ваша карта используется только для перебора элементов, и скорость итерации важна, то преобразование карты в ArrayList и повторение ее, это будет самый быстрый способ.
Ответ 4
Я бы не использовал карту. Если все, что вам нужно, - это перебирать записи, создайте новый 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
до ArrayList
по предложению Марко.
Ответ 5
Я согласен с ответом Zim-Zam и добавляю что-то: если вам нужно получить доступ к ключам и значениям во время итерации, самый быстрый способ - entrySet()
, как обсуждалось здесь.
Теперь, если вы уверены, что карта никогда не изменится, почему бы не использовать отдельную структуру данных для итерации? например: повторить по завершенной карте и заполнить ее содержимым пару массивов, один с ключами, а другой со значениями в тех же соответствующих положениях. Тогда перемещение этих массивов будет таким же быстрым, насколько это возможно.
Ответ 6
Map.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;
}
}