Как использовать новую функцию computeIfAbsent?
Я очень хочу использовать карта.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)));
но в их примере, я думаю, что я не совсем " получаю это."Как бы я преобразовал код, чтобы использовать новый лямбда-способ выражения этого?
5 ответов:
Предположим, у вас есть следующий код:
import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class Test { public static void main(String[] s) { Map<String, Boolean> whoLetDogsOut = new ConcurrentHashMap<>(); whoLetDogsOut.computeIfAbsent("snoop", k -> f(k)); whoLetDogsOut.computeIfAbsent("snoop", k -> f(k)); } static boolean f(String s) { System.out.println("creating a value for \""+s+'"'); return s.isEmpty(); } }тогда вы увидите сообщение
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);еслиtryToLetOutиstaticилиwhoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut);еслиtryToLetOut- это метод экземпляра.
недавно я тоже играл с этим методом. Я написал мемуарный алгоритм для вычисления чисел Фибоначчи, которые могут служить еще одной иллюстрацией того, как использовать этот метод.
мы можем начать с определения карты и размещения в ней значений для базовых случаев, а именно:
fibonnaci(0)иfibonacci(1):private static Map<Integer,Long> memo = new HashMap<>(); static { memo.put(0,0L); //fibonacci(0) memo.put(1,1L); //fibonacci(1) }и для индуктивного шага все, что нам нужно сделать, это переопределить нашу функцию Фибоначчи следующим образом:
public static long fibonacci(int x) { return memo.computeIfAbsent(x, n -> fibonacci(n-2) + fibonacci(n-1)); }Как видите, метод
computeIfAbsentбудет используйте предоставленное лямбда-выражение для вычисления числа Фибоначчи, когда это число отсутствует на карте. Это представляет собой значительное улучшение по сравнению с традиционным, рекурсивным алгоритмом дерева.
другой пример. При построении сложной карты карт метод computeIfAbsent() является заменой метода get () карты. Через цепочку вызовов computeIfAbsent () вместе недостающие контейнеры строятся на лету с помощью предоставленных лямбда-выражений:
// Stores regional movie ratings Map<String, Map<Integer, Set<String>>> regionalMovieRatings = new TreeMap<>(); // This will throw NullPointerException! regionalMovieRatings.get("New York").get(5).add("Boyhood"); // This will work regionalMovieRatings .computeIfAbsent("New York", region -> new TreeMap<>()) .computeIfAbsent(5, rating -> new TreeSet<>()) .add("Boyhood");
Это очень полезно, если вы хотите создать Multimap без использования библиотеки guava(https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html)
например: если вы хотите сохранить список студентов, которые поступили на определенный предмет. Нормальным решением для этого с помощью библиотеки jdk является
Map<String,List<String>> studentListSubjectWise = new TreeMap<>(); List<String>lis = studentListSubjectWise.get("a"); if(lis == null) { lis = new ArrayList<>(); } lis.add("John"); //continue....поскольку у него есть код котельной плиты, люди, как правило, используют guava Mutltimap.
используя Карта.computeIfAbsent, мы можем написать в одной строке без Guava Multimap следующим образом.
studentListSubjectWise.computeIfAbsent("a", (x -> new ArrayList<>())).add("John");Стюарт Маркс и Брайан Гетц хорошо поговорили об этом https://www.youtube.com/watch?v=9uTVXxJjuco
нет никакой разницы между использованием computeIfAbsent () и simple put () get ()
функции карте. Другими словами, вы можете переписать свою функцию таким образомfor (char ch : input){ Integer value; if(countMap.containsKey(ch)){ value = countMap.get(ch); value++; countMap.put(ch, value); } else{ value = 1; countMap.put(ch, value); } }
Comments