java.util.Map values ​​() производительность метода - PullRequest
0 голосов
/ 05 мая 2018

У меня есть такая карта с несколькими миллионами записей:

private final Map<String, SomeItem> tops = new HashMap<>();

Мне нужно получить список значений, что можно сделать, вызвав метод java.util.Map values().

Вопрос :

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

Проблема в том, что в моем случае Map содержит несколько миллионов элементов, и я не хочу создавать новый список каждый раз, когда values() называется

Ответы [ 4 ]

0 голосов
/ 06 мая 2018

Еще одно предложение после прочтения этой темы, если объявленное содержимое вершин Карты не изменилось - вы можете использовать объект gmm guava ImmutableMap. Для получения дополнительной информации - UnmodifiableMap (Коллекции Java) против ImmutableMap (Google)

0 голосов
/ 05 мая 2018

Как уже упоминали другие, вы можете увидеть это, посмотрев на код. Вы также можете написать быстрый пример, чтобы доказать это себе. Приведенный ниже код напечатает true 10 раз, так как идентификатор объекта всегда будет одинаковым для значений.

public static void main(String[] args) {
    Map<String, String> myMap = new HashMap();
    Collection<String> lastValues = myMap.values();
    for (int i=0; i < 10; i++) {
        System.out.println(lastValues == myMap.values());
        lastValues = myMap.values();
    }
}

Следующий код напечатает true в первый раз, а затем false в следующие 9 раз.

public static void main(String[] args) {
    Map<String, String> myMap = new HashMap();
    Collection<String> lastValues = myMap.values();
    for (int i=0; i < 10; i++) {
        System.out.println(lastValues == myMap.values());
        lastValues = myMap.values();
        myMap = new HashMap();
    }
}
0 голосов
/ 05 мая 2018

Один важный момент здесь может быть: Это не имеет значения!


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

public Collection<V> values() {
    Collection<V> vs;
    return (vs = values) == null ? (values = new Values()) : vs;
}

Это даже указано (как часть контракта, как спецификация реализации) в документации класса AbstractMap (на которой основано большинство реализаций Map):

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


Но теперь можно утверждать, что реализация может измениться позже. Реализация класса HashMap может измениться, или одна может переключиться на другую реализацию Map, которая не расширяет AbstractMap и которая реализована по-другому. Тот факт, что он в настоящее время реализован таким образом, (для себя) не гарантирует, что он всегда будет реализован таким образом.

Итак, более важный момент (и причина, по которой не имеет значения ), заключается в том, что метод values() действительно должен возвращать представление коллекции . Как указано в документации Map интерфейса :

Интерфейс Map предоставляет три представления коллекции , которые позволяют просматривать содержимое карты в виде набора ключей, набора значений или набора сопоставлений значения ключа.

и, в частности, документация по методу Map#values() :

Возвращает коллекционное представление значений, содержащихся в этой карте. Коллекция поддерживается картой, поэтому изменения в карте отражаются в коллекции и наоборот.

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


Так, например, представьте, что реализация в HashMap была такой:

public Collection<V> values() {
    return new Values();
}

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

Или, если выразиться так: Стоимость вызова этого метода составляет независимо от размера карты. В основном это стоимость создания одного объекта, независимо от того, содержит ли карта 10 или 10000 элементов.

0 голосов
/ 05 мая 2018

Ниже приведена копия Map.values() в java.util.HashMap:

public Collection<V> values() {
    Collection<V> vs = values;
    if (vs == null) {
        vs = new Values();
        values = vs;
    }
    return vs;
}

Это ясно показывает, что коллекция значений не создается без необходимости. Таким образом, не должно быть дополнительных накладных расходов, вызванных вызовами values()

...