Рубрики
Без рубрики

Сопоставьте лучшие практики

Сегодняшняя тема посвящена карте и злоупотреблениям, которые я видел во время многих обзоров кода. Идея с картой состоит в том, чтобы… Помеченный java.

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

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

В Java 8 были добавлены некоторые полезные новые методы. Допустим, вы хотите проверить, есть ли что-то на карте :

  • Если это так, верните его
  • Если это не так, добавьте его и верните

Классический способ сделать это таков:

if (map.containsKey(key)) { // one hash
    return map.get(key); // two hash
}
List list = new ArrayList<>();
map.put(key, list); // three hash
return list;

Он также самый медленный. Лучший способ – это:

List list = map.get(key); // one hash
if(list == null) {
    list = new ArrayList<>();
    map.put(key, list); // two hash
}
return list;

Это уже намного лучше. Вы экономите один хэш.

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

Но начиная с Java 8, у вас есть три лучших решения.

Первый из них – это:

map.putIfAbsent(key, new ArrayList<>()); // one hash
return map.get(key); // two hash

Это лучше, но ненамного. У вас все еще есть два хэша. И ArrayList создается, даже если он уже есть на карте.

Вы можете совершенствоваться с более длительным:

List list = new ArrayList<>();
List result = map.putIfAbsent(key, list); // one hash only!
if(result == null) {
    return list;
}
return result;

Теперь мы говорим только об одном хэше! Но все равно ArrayList создается бесполезно.

Что подводит нас к другому методу Java 8, который делает свое дело.

return map.computeIfAbsent(key, unused -> new ArrayList<>()); // one hash only!

Работа выполнена. Одна линия и самая быстрая, которую мы можем получить. Экземпляр ArrayList будет создаваться только при необходимости.

Важно: Не делайте map.computeIfAbsent(ключ, список массивов::новый) . computeIfAbsent принимает функцию<КЛЮЧ, ЗНАЧЕНИЕ> в качестве параметра. Таким образом, это, как правило, не будет компилироваться, если КЛЮЧ не соответствует параметру одного из конструкторов ArrayList. Примером может служить случай, когда КЛЮЧ является целым числом. Передача ссылки на метод конструктора фактически вызовет новый список массивов (КЛЮЧ) … что, очевидно, не то, что вы хотите.

Чтобы убедить вас в том, что это лучшее решение, я провел небольшой тест с использованием JMH. Вот результаты:

Benchmark                               Mode  Cnt         Score        Error  Units
MapBenchmark.computeIfAbsent_there     thrpt   40  25134018.341 ± 687925.885  ops/s (the best!)
MapBenchmark.containsPut_there         thrpt   40  21459978.028 ± 401003.399  ops/s
MapBenchmark.getPut_there              thrpt   40  24268773.005 ± 690893.070  ops/s
MapBenchmark.putIfAbsentGet_there      thrpt   40  18230032.343 ± 238803.546  ops/s
MapBenchmark.putIfAbsent_there         thrpt   40  20579085.677 ± 527246.125  ops/s

MapBenchmark.computeIfAbsent_notThere  thrpt   40   8229212.547 ± 341295.641  ops/s (the best!)
MapBenchmark.containsPut_notThere      thrpt   40   6996790.450 ± 191176.603  ops/s
MapBenchmark.getPut_notThere           thrpt   40   8009163.041 ± 288765.384  ops/s
MapBenchmark.putIfAbsentGet_notThere   thrpt   40   6212712.165 ± 333023.068  ops/s
MapBenchmark.putIfAbsent_notThere      thrpt   40   7227880.072 ± 289581.816  ops/s

До следующего раза: Счастливого картографирования.

Оригинал: “https://dev.to/henritremblay/map-best-practices-7ok”