Java Map computeIfAbsent()

Метод Map.computeIfAbsent() вычисляет сопоставленное значение для ключа с помощью функции сопоставления, если указанный ключ не существует в Map или сопоставлен со значением null. Он был добавлен как метод по умолчанию в интерфейс Map в Java 8.

1. Когда использовать метод computeIfAbsent()?

1.1 Когда функция Mapper является дорогостоящей операцией

Map.computeIfAbsent() следует использовать, когда вычисление значения является «дорогостоящей операцией». Например, если Map хранит число как ключ, а его факториал как значение, то мы можем использовать computeIfAbsent(), поскольку вычисление факториала является операцией, интенсивно использующей память.

 Карта карта = new HashMap<>();map.computeIfAbsent(5, Main::factorial);map.computeIfAbsent(6, Main::factorial);//Вставка в другое местоmap.computeIfAbsent(6, Main::factorial); //Факториал здесь не вычисляетсястатический BigInteger факториал(Integer num) {System.out.println("Вычисление факториала числа : " + num);вернуть BigIntegerMath.factorial(число);}

Программа выводит операторы печати только два раза. В третий раз, поскольку ключ уже существует в Map, функция mapper не вызывается и факториал не вычисляется.

Calculating the factorial of : 5Calculating the factorial of : 6

1.2 Создание мультикарты

Другое распространенное использование computeIfAbsent() — создание многозначной карты. Многозначная карта сопоставляет один ключ с несколькими значениями, обычно в списке.

В следующем примере первый вызов с «State1» приведет к созданию нового списка, сопоставлению его с ключом и добавлению к нему «City1». При втором вызове, поскольку ключ «State1» уже присутствует, новый список не будет создан, а «City2» будет добавлен к существующему списку.

Map<String, List<String>> multiMap = new HashMap<>();multiMap.computeIfAbsent("State1", k -> new ArrayList<>()).add("City1");multiMap.computeIfAbsent("State1", k -> new ArrayList<>()).add("City2");System.out.println(multiMap); //{State1=[City1, City2]}

2. Синтаксис Map.computeIfAbsent()

Синтаксис метода:

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

Параметры

Функция computeIfAbsent() принимает два параметра:

  • ключ: ключ для сохраняемого сопоставления.
  • mappingFunction: ненулевая функция сопоставления будет вызвана только в том случае, если заданный ключ не сопоставлен ни с каким значением. Она вычисляет новое значение для указанного ключа.

Возвращаемое значение

ComputeIfAbsent() возвращает текущее значение(новое или старое), связанное с ключом после вычисления. Он может вернуть null, если с ключом не связано ни одно значение.

Если результат mappingFunction равен нулю, то сопоставление для указанного ключа удаляется.

3. Как использовать функцию Mapper?

Давайте рассмотрим несколько примеров, чтобы лучше понять использование метода.

3.1. Функция Mapper не должна быть NULL

Функция отображения должна быть ненулевой, иначе будет выброшено исключение NullPointerException. В следующем коде мы передаем null в качестве функции отображения, поэтому она выдаст исключение NullPointerException.

Map<Integer, BigInteger> map = new HashMap<>();map.computeIfAbsent(6, null);

3.2. Функция Mapper может возвращать NULL

Могут быть случаи, когда функция отображения возвращает нулевые значения. В таком сценарии запись не создается в Map, но операция не выдает никаких исключений.

Map<Integer, BigInteger> map = new HashMap<>();map.computeIfAbsent(7, k -> null); //No entry is created in the mapassertNull( map.get(7) );

3.3 Функция Mapper, выдающая непроверенное исключение

В случае, если функция сопоставления выдает непроверенное исключение, исключение выдается повторно, и запись в карте не создается.

В следующем коде функция mapper выдала исключение, когда мы попытались добавить ключ 7. В блоке catch мы подтверждаем, что запись не была создана в Map.

try {map.computeIfAbsent(7, k-> {throw new RuntimeException();});} catch(Exception e) {assertNull( map.get(7) );}

4. Разница с compute() и computeIfPresent()

Интерфейс карты имеет 3 метода вычислений.

  • вычислить()
  • computeIfPresent()
  • computeIfAbsent()

Эти функции выглядят одинаково, но это не так. Compute() и computeIfPresent() используют BiFunction как функцию переназначения. Она принимает указанный ключ и текущее сопоставленное значение в качестве аргументов метода и пытается вычислить новое сопоставление.

Compute() всегда вызывает функцию сопоставления, тогда как computeIfPresent() вызывает функцию сопоставления только тогда, когда значение присутствует для указанного ключа и оно не равно NULL.

Map<Integer, BigInteger> map = new HashMap<>();map.put(1, null);map.computeIfPresent(1,(k, v) -> Main.factorial(k)); //factorial is not executedmap.compute(1,(k, v) -> Main.factorial(k)); //factorial is executed

5. Заключение

В этой статье мы рассмотрели метод Map.computeIfAbsent() из Java 8. Мы узнали, когда использовать этот метод и как обрабатывать значения NULL и исключения. Мы также сравнили его с методами compute() и computeIfPresent().

Исходный код на Github

Прокрутить вверх