Использует java Map.containsKey () избыточен при использовании map.получить()

мне было интересно в течение некоторого времени, допустимо ли в рамках лучшей практики воздерживаться от использования containsKey() метод on java.util.Map и вместо этого сделайте нулевую проверку результата от get().

мое обоснование заключается в том, что кажется избыточным выполнять поиск значения дважды - сначала для containsKey() и затем на get().

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

Я был бы очень признателен за ваши комментарии.

5 ответов


некоторые реализации карты могут иметь нулевые значения, например HashMap, в этом случае, если get(key) возвращает null это не гарантирует, что нет записи в карте, связанной с этим ключом.

Итак, если вы хотите знать, содержит ли карта ключ use Map.containsKey. Если вам просто нужно значение, сопоставленное с ключом, используйте Map.get(key). Если эта карта допускает значения NULL, то возвращаемое значение null не обязательно означает, что карта не содержит отображения для ключа; в таком случае Map.containsKey бесполезно и повлияет на производительность. Более того, в случае параллельного доступа к карте (например,ConcurrentHashMap), после того, как вы протестировали Map.containsKey(key) существует вероятность того, что запись будет удалена другим потоком перед вызовом Map.get(key).


Я думаю, что это довольно стандартно писать:

Object value = map.get(key);
if (value != null) {
    //do something with value
}

вместо

if (map.containsKey(key)) {
    Object value = map.get(key);
    //do something with value
}

это не менее читабельно и немного более эффективно, поэтому я не вижу причин не делать этого. Очевидно если ваша карта может содержать null, эти два параметра не имеют одинаковой семантики.


Как указал ассилий, это семантический вопрос. В Общем, Карта.get (x) == null-это то, что вы хотите, но есть случаи, когда важно использовать containsKey.

одним из таких случаев является кэш. Однажды я работал над проблемой производительности в веб-приложении, которое часто запрашивало свою базу данных в поисках несуществующих сущностей. Когда я изучил код кэширования для этого компонента, я понял, что он запрашивает базу данных, если кэш.get (key) == null. Если база данных возвращена null (сущность не найдена), мы будем кэшировать этот ключ -> null mapping.

переключение на containsKey решило проблему, потому что сопоставление с нулевым значением на самом деле что-то значило. Сопоставление ключа с null имело другое семантическое значение, чем несуществующий ключ.


мы можем сделать ответ @assylias более читаемым с Java8 необязательным,

Optional.ofNullable(map.get(key)).ifPresent(value -> {
     //do something with value
};)

в Java, если вы проверяете реализации

public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}

public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

оба используют getNode для получения соответствия, где выполняется основная работа.

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

делаешь...

if(dictionary.containsKey(word)) {
   return dictionary.get(word);
}

избыточна.

но если вы хотите, чтобы проверить слово действительно или не на основе словаря. делающий...

 return dictionary.get(word) != null;

более...

 return dictionary.containsKey(word);

избыточна.

если вы проверяете поиска HashSet реализация, которая использует HashMap внутренне, используйте "containsKey" в методе "contains".

    public boolean contains(Object o) {
        return map.containsKey(o);
    }