1. ホーム
  2. java

[解決済み] 新しい関数computeIfAbsentの使い方を教えてください。

2022-03-03 17:57:24

質問

をぜひ使いたい。 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)));

しかし、彼らの例では、私はそれを理解することができないようです。

どのように解決するのですか?

次のようなコードがあったとします。

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" の2回目の起動のときと同じように、1回だけ 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); もし tryToLetOutstatic または whoLetDogsOut.computeIfAbsent("snoop", this::tryToLetOut); もし tryToLetOut はインスタンスメソッドです。