Jdk 8のConcurrent Hash Mapの新しいバージョンには、2つの新しいメソッドがあります。
computeIfAbsent
computeIfPresent
putIfAbsent-古いメソッド
putIfAbsentおよびcomputeIfAbsentの使用例を理解しています。しかし、いつcomputeIfPresentを使用するのか、シナリオはわかりません。また、computeIfPresentがあるのに、なぜputIfAbsentが必要なのですか。 putIfAbsentは、値のインスタンスを少なくとも1つ追加作成します。
理由は、下位互換性を維持するためだけですか?
他の回答で述べたように、新しい「より強力な」メソッドが導入された場合でも、メソッドは常に下位互換性のために保持されます。
computeIfPresent
の使用例について:不自然に見えなくても納得できるほど小さい例を見つけるのは難しいかもしれません。一般に、このメソッドの目的は、既存の値を任意の形式でupdateすることです。
1つの例は、(制約付き)単語数の場合があります。特定の単語セットに対して、マップに0
の初期数を格納します。次に、単語のシーケンスが処理されます。最初のセットから単語が見つかるたびに、そのカウントが1ずつ増加します。
import Java.util.LinkedHashMap;
import Java.util.Map;
public class ComputeIfPresentExample
{
public static void main(String[] args)
{
Map<String, Integer> wordCounts = new LinkedHashMap<String, Integer>();
String s =
"Lorem ipsum dolor sit amet consetetur iam nonumy sadipscing " +
"elitr, sed diam nonumy eirmod tempor invidunt ut erat sed " +
"labore et dolore magna dolor sit amet aliquyam erat sed diam";
wordCounts.put("sed", 0);
wordCounts.put("erat", 0);
for (String t : s.split(" "))
{
wordCounts.computeIfPresent(t, (k,v) -> v+1);
}
System.out.println(wordCounts);
}
}
(もちろん、このようなことは別の方法で解決することもできますが、これはどちらか一方の形式ではかなり頻繁なタスクであり、新しい方法ではかなり簡潔でエレガントなソリューションが可能になります)
一般的な使用例は maps と collections で、次のようになります。
Map<String, Collection<String>> strings = new HashMap<>();
computeIfAbsent
および computeIfPresent
は、コレクションへの要素の追加およびコレクションからの要素の削除に非常に便利な操作です。文字列を最初の文字でグループ化する例を次に示します。キーとコレクションの両方が必要なときに作成され、コレクションが空になったときにクリーンアップされることに注意してください。
void addString(String a) {
String index = a.substring(0, 1);
strings.computeIfAbsent(index, ign -> new HashSet<>()).add(a);
}
void removeString(String a) {
String index = a.substring(0, 1);
strings.computeIfPresent(index, (k, c) -> {
c.remove(a);
return c.isEmpty() ? null : c;
});
}
ConcurrentMaps
はこれらの操作をアトミックに実行するため、これはマルチスレッド環境で非常に強力です。
例:
// {}
addString("a1"); // {a=[a1]} <-- collection dynamically created
addString("a2"); // {a=[a1, a2]}
removeString("a1"); // {a=[a2]}
removeString("a2"); // {} <-- both key and collection removed
いくつかの余分な砂糖:
void addString(String a) {
String index = a.substring(0, 1);
strings.computeIfAbsent(index, ign -> new HashSet<>()).add(a);
}
void removeString(String a) {
String index = a.substring(0, 1);
strings.computeIfPresent(index, (i, c) -> c.remove(a) && c.isEmpty() ? null : c);
}
文字列のマップから小文字の値をフェッチするnullセーフな方法として、computeIfPresentを使用しました。
String s = fields.computeIfPresent("foo", (k,v) -> v.toLowerCase())
ComputeIfPresentが利用可能になる前に、私はこれを行わなければなりませんでした:
String s = map.get("foo");
if (s != null) {
s = s.toLowerCase();
}
またはこれ:
String s = map.containsKey("foo") ? map.get("foo").toLowerCase() : null;
JDKは後方互換性をほとんど壊しません。それは、古いバージョンから最新バージョンのソフトウェアを簡単に移植または実行できないためです。
古いバージョンのライブラリでコンパイルされたソフトウェアを、それらの機能が残っている任意のバージョン(JREがインストールされているユーザー)で実行できます。