Я очень хочу использовать Map.computeIfAbsent, но с тех пор, как лямбды не использовались в старших классах, прошло слишком много времени.
Практически прямо из документации: он дает пример старого способа делать что-то:
Map<String, Boolean> whoLetDogsOut = new ConcurrentHashMap<>();
String key = "snoop";
if (whoLetDogsOut.get(key) == null) {
Boolean isLetOut = tryToLetOut(key);
if (isLetOut != null)
map.putIfAbsent(key, isLetOut);
}
И новый способ:
map.computeIfAbsent(key, k -> new Value(f(k)));
Но в их примере, я думаю, я не совсем «понимаю». Как мне преобразовать код, чтобы использовать новый лямбда-способ выражения этого?
java
dictionary
lambda
java-8
Бенджамин Х
источник
источник
Ответы:
Предположим, у вас есть следующий код:
Тогда вы увидите сообщение
creating a value for "snoop"
ровно один раз, так как при втором вызовеcomputeIfAbsent
уже есть значение для этого ключа. Вk
лямбда-выраженииk -> f(k)
просто подставка (параметр) для ключа, который карта передаст вашей лямбда-выражению для вычисления значения. Итак, в этом примере ключ передается при вызове функции.В качестве альтернативы вы можете написать:
whoLetDogsOut.computeIfAbsent("snoop", k -> k.isEmpty());
для достижения того же результата без вспомогательного метода (но тогда вы не увидите вывод отладки). И что еще проще, так как это простое делегирование существующему методу, которое вы могли бы написать:whoLetDogsOut.computeIfAbsent("snoop", String::isEmpty);
Это делегирование не требует записи каких-либо параметров.Чтобы быть ближе к примеру в вашем вопросе, вы можете написать его как
whoLetDogsOut.computeIfAbsent("snoop", key -> tryToLetOut(key));
(неважно, назовете ли вы параметрk
илиkey
). Или напишите его какwhoLetDogsOut.computeIfAbsent("snoop", MyClass::tryToLetOut);
iftryToLetOut
isstatic
илиwhoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);
iftryToLetOut
is a instance method.источник
Недавно тоже поигрался с этим методом. Я написал мемоизированный алгоритм для вычисления чисел Фибоначчи, который может служить еще одной иллюстрацией того, как использовать этот метод.
Мы можем начать с определения карты и помещения в нее значений для базовых случаев, а именно,
fibonnaci(0)
иfibonacci(1)
:А для индуктивного шага все, что нам нужно сделать, это переопределить нашу функцию Фибоначчи следующим образом:
Как видите, метод
computeIfAbsent
будет использовать предоставленное лямбда-выражение для вычисления числа Фибоначчи, когда число не присутствует на карте. Это представляет собой значительное улучшение по сравнению с традиционным древовидным рекурсивным алгоритмом.источник
HashMap
к повреждению внутренних компонентов, как и в случае с bugs.openjdk.java.net/browse/JDK-8172951, и не работает сConcurrentModificationException
Java 9 ( bugs.openjdk.java.net/browse/JDK-8071667 )Другой пример. При построении сложной карты карт метод computeIfAbsent () заменяет метод get () карты. Посредством объединения вызовов computeIfAbsent () недостающие контейнеры создаются на лету с помощью предоставленных лямбда-выражений:
источник
мульти-карта
Это действительно полезно, если вы хотите создать мульти-карту, не прибегая к библиотеке Google Guava для реализации
MultiMap
.Например, предположим, что вы хотите сохранить список студентов, поступивших на определенный предмет.
Обычное решение для этого с использованием библиотеки JDK:
Поскольку у него есть шаблонный код, люди склонны использовать Guava
Mutltimap
.Используя Map.computeIfAbsent, мы можем написать в одной строке без guava Multimap следующим образом.
Стюарт Маркс и Брайан Гетц хорошо обсудили это https://www.youtube.com/watch?v=9uTVXxJjuco
источник
studentListSubjectWise.stream().collect(Collectors.GroupingBy(subj::getSubjName, Collectors.toList());
мульти-карту в Java 8 (и более сжатый) - просто сделать. Это создает мульти-карту типаMap<T,List<T>
в JDK, только более кратко, imho.