https://twitter.com/cero_t/status/1305994285897011200 の話。
Map<String, Integer> someKeyName2ValueName = new LinkedHashMap<>(Map.of(
"foo", 10,
"bar", 20,
"baz", 30
));
順序を保持する必要があるので Map.of
をコンストラクタに渡す手は残念ながら使えません。
Map<String, Integer> someKeyName2ValueName = new LinkedHashMap<>() {{
put("foo", 10);
put("bar", 20);
put("baz", 30);
}};
たまにこのイディオムを見かけますが、これをインスタンススコープで行うと、
someKeyName2ValueName
に代入されたMapインスタンスがエンクロージングクラスのインスタンス参照を保持してしまうので、
メモリリークや直列化で問題が発生したりします。
Map<String, Integer> someKeyName2ValueName = new LinkedHashMap<>();
someKeyName2ValueName.put("foo", 10);
someKeyName2ValueName.put("bar", 20);
someKeyName2ValueName.put("baz", 30);
一番王道だと思われます。スコープが区切れないのと変数名が長いとうざったいというのはありますね。
ブロックを用いてこの辺軽減する手もあったりします。
Map<String, Integer> someKeyName2ValueName;
{
var m = new LinkedHashMap<String, Integer>();
m.put("foo", 10);
m.put("bar", 20);
m.put("baz", 30);
someKeyName2ValueName = m;
}
public static <A> A tap(A a, Consumer<? super A> f) {
f.accept(a);
return a;
}
こういうメソッドをユーティリティとして用意しておくと以下のように書けます。
Map<String, Integer> someKeyName2ValueName = tap(new LinkedHashMap<>(), m -> {
m.put("foo", 10);
m.put("bar", 20);
m.put("baz", 30);
});
Kotlin や Scala には標準で用意されてるので便利ですね。(それらの言語の場合はそもそも別のより良い方法がありますが)