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

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

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

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

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

Ответ 1

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

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

Ответ 2

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

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
}

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

Ответ 3

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

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

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

Ответ 4

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

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