3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Map#computeIfAbsentでいろいろ混乱した話

Posted at

Map#computeIfAbsentはJava8で追加されたメソッドで、かれこれ5年も経ってるのに、知ったのは1年ほど前でした。

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

keyに該当する値が存在しない場合は、mappingFunctionが呼び出され、その戻り値がMapに格納されて返却してくれます。

ConcurrentHashMap

あるWebシステムでデータをキャッシュする処理を実装するにあたり疑問が湧きました。

private Map<String, String> cache = new ConcurrentHashMap<>()

public String get(String id) {
  return cache.computeIfAbsent(key, key -> {
    if (/* キーに該当する外部ファイルが存在する */) {
      // ファイルを読み込んで返却
      return readData;
    }
    // 該当するファイルがない
    return null;
  });
}

ConcurrentHashMapは値にnullが持てないのに、nullを返却して大丈夫なんだろうか?
ということでテストコードで実験してみました。

Map<String, String> map = new ConcurrentHashMap<>();
String ret = map.computeIfAbsent("test", key -> null);
System.out.println(ret);

実行結果は例外が発生することもなく、戻り値はnullでした。
これはJavadocにもちゃんと書いてありましたね。。。

指定されたキーがまだ値に関連付けられていない場合、指定されたマッピング関数を使用してその値の計算を試行し、
nullでない場合はそれをこのマップに入力します。

Kotlin

見ての通り上記はJavaで書いてますが、システム開発も序盤なのでKotlinにコードを書き換えたところコンパイルエラーになりました。Kotlinのバージョンは1.3.31です。

val cache = ConcurrentHashMap<String, String>()

fun get(id: String): String? {
  return cache.computeIfAbsent(id) {
    if (/* キーに該当する外部ファイルが存在する */) {
      // ファイルを読み込んで返却
      return readData;
    }
    return null; // エラー! Kotlin: Null can not be a value of a non-null type String
  }
}

KotlinのAPIリファレンスによるとMap.get

operator fun get(key: K): V?

とVがnull許容にしてくれているけど、mappingFunctionの戻り値はVのままのようです。
回避策として

val ret: String? = map.computeIfAbsent("test") { null!! }

のように!!を付ければコンパイルエラーは解決するものの、実行時にkotlin.KotlinNullPointerExceptionが発生する始末。。。orz

解決策としては

val map = ConcurrentHashMap<String, String?>()
val ret: String? = map.computeIfAbsent("test") { null }

Vを最初からnull許容で宣言するぐらいしか判りませんでした。
でも、これだとgetの戻り値がString??なんて変な型にならないかと心配したら流石にそんなこともなく、String?にしたことで今の所不便も見つかってないので、これで正解なのかなぁ。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?