Сегодняшняя тема посвящена Карта и злоупотребления, которые я видел во время многих обзоров кода.
Идея с Картой состоит в том, чтобы делать все, что вам нужно, делая как можно меньше хеширования. Хэш возникает каждый раз, когда вы обращаетесь к Карте (например, получить , Содержит клавишу , поставить ).
В 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;
Он также самый медленный. Лучший способ – это:
Listlist = 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 создается, даже если он уже есть на карте.
Вы можете совершенствоваться с более длительным:
Listlist = 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”