1. 概要

In this tutorial, we’ll discuss the new default method, computeIfAbsent, of the Map interface introduced in Java 8.

Specifically, we’ll look at its signature, usage, and how it handles different cases.

2. Map.computeIfAbsentメソッド

computeIfAbsentの署名を見てみましょう。

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

computeIfAbsentメソッドは2つのパラメーターを取ります。 The first parameter is the key, and the second parameter is the mappingFunction. It’s important to know that the mapping function is only called if the mapping isn’t present.

2.1. 非ヌル値に関連するキー

First, it checks if the key is present in the map. If the key is present, and a non-null value is related to the key, then it returns that value:

Map<String, Integer> stringLength = new HashMap<>();
stringLength.put("John", 5);
assertEquals((long)stringLength.computeIfAbsent("John", s -> s.length()), 5);

As we can see, the key “John” has a non-null mapping present, and it returns the value 5. If our mapping function was used, we’d expect the function to return the length of 4.

2.2. マッピング関数を使用した値の計算

Furthermore, if the key isn’t present in the map, or the null value is related to the key, then it attempts to compute the value using the given mappingFunction. It also enters the calculated value into the map unless the calculated value is null.

Let’s take a look at the use of the mappingFunction in the computeIfAbsent method:

Map<String, Integer> stringLength = new HashMap<>();
assertEquals((long)stringLength.computeIfAbsent("John", s -> s.length()), 4);
assertEquals((long)stringLength.get("John"), 4);

Since the key “John” isn’t present, it computes the value by passing the key as a parameter to the mappingFunction.

2.3. マッピング関数はnullを返します

また、mappingFunctionnullを返す場合、マップはマッピングを記録しません。

Map<String, Integer> stringLength = new HashMap<>();
assertEquals(stringLength.computeIfAbsent("John", s -> null), null);
assertNull(stringLength.get("John"));

2.4. マッピング関数は例外をスローします

最後に、 mappingFunction がチェックされていない例外をスローした場合、例外は再スローされ、マップはマッピングを記録しません。

@Test(expected = RuntimeException.class)
public void whenMappingFunctionThrowsException_thenExceptionIsRethrown() {
    Map<String, Integer> stringLength = new HashMap<>();
    stringLength.computeIfAbsent("John", s -> { throw new RuntimeException(); });
}

We can see that the mappingFunction throws a RuntimeException, which propagates back to the computeIfAbsent method.

3. 結論

In this brief article, we focused on the computeIfAbsent method, its signature, and its usage. Finally, we learned how it handles different cases.

As always, all of these code samples are available over on GitHub.