Java 8以降でMapに追加されたメソッドたち
この記事は何?
Javaでマップはちょいちょい使いますね。この記事では、Java 8以降で導入された比較的新しいメソッドを中心に紹介します。
環境
JDK 21
超基本的な使い方
put()
で値の追加、get()
で値の取得ができますね。
// マップを生成
Map<String, Integer> fruitsMap = new HashMap<>();
// マップにフルーツの名前と数量を追加
fruitsMap.put("apple", 10);
fruitsMap.put("banana", 20);
fruitsMap.put("orange", 30);
// リンゴの数量を取得
int appleCount = fruitsMap.get("apple");
System.out.println("リンゴの数量: " + appleCount);
リンゴの数量: 10
マップの生成は Map.of()
で簡潔に書くこともできます。ただし、これはイミュータブル(不変)なマップを生成するので、後から値を追加することはできません(put()
するとjava.lang.UnsupportedOperationException
がスローされます)。
// マップを生成
Map<String, Integer> fruitsMap = Map.of(
"apple", 10,
"banana", 20,
"orange", 30
);
// リンゴの数量を取得
int appleCount = fruitsMap.get("apple");
System.out.println("リンゴの数量: " + appleCount);
他にもこんなメソッドがあります。
-
containsKey()
: キーが存在すればtrue
を返す -
containsValue()
: 値が存在すればtrue
を返す -
size()
: マップのサイズを取得 -
isEmpty()
: マップが空であればtrue
を返す -
remove()
: キーと値のペアを削除
マップの内容を全て表示する
マップの内容を全て表示するには、forEach()
メソッドを使います。
ただし、マップは基本的に順序を保証しないため、マップ生成時に指定した順に表示されるとは限りません。
// マップを生成
Map<String, Integer> fruitsMap = Map.of(
"apple", 10,
"banana", 20,
"orange", 30
);
// マップの内容を表示
fruitsMap.forEach((k, v) -> System.out.println("フルーツ: " + k + ", 数量: " + v));
フルーツ: banana, 数量: 20
フルーツ: orange, 数量: 30
フルーツ: apple, 数量: 10
マップをリストに変換する
マップの内容をリストに変換するには、entrySet()
メソッドを使ってエントリーセットを取得し、それをストリームに変換してリストに収集します。
エントリーは、マップのキーと値のペアを保持するものです。エントリーセットは、マップの全ペアのエントリーを保持します。
今回は、フルーツの名前と数量を持つ FruitStock
クラスを定義し、それを使ってマップの内容をリストに変換します。
// フルーツの名前と数量を持つレコード
record FruitStock(String name, int quantity) {
}
// マップを生成
Map<String, Integer> fruitsMap = Map.of(
// マップにフルーツの名前と数量を追加
"apple", 10,
"banana", 20,
"orange", 30
);
// マップをリストに変換
List<FruitStock> stockList = fruitsMap.entrySet()
.stream()
.map(entry -> new FruitStock(entry.getKey(), entry.getValue()))
.toList();
System.out.println("フルーツの在庫リスト:" + stockList);
フルーツの在庫リスト:[FruitStock[name=apple, quantity=10], FruitStock[name=orange, quantity=30], FruitStock[name=banana, quantity=20]]
キーが存在しない場合にデフォルト値を返す
get()
の引数に指定したキーがマップに存在しない場合、null
が返されます。getOrDefault()
メソッドを使うと、キーが存在しない場合にデフォルト値を返すことができます。
// マップを生成
Map<String, Integer> fruitsMap = Map.of(
// マップにフルーツの名前と数量を追加
"apple", 10,
"banana", 20,
"orange", 30
);
// キーが存在するので値10を返す
int appleCount = fruitsMap.getOrDefault("apple", 0);
System.out.println("リンゴの数量: " + appleCount);
// キーが存在しないのでデフォルト値0を返す
int melonCount = fruitsMap.getOrDefault("melon", 0);
System.out.println("メロンの数量: " + melonCount);
リンゴの数量: 10
メロンの数量: 0
キーが存在しない場合のみ値を追加する
putIfAbsent()
メソッドを使うと、キーが存在しない場合にのみ値を追加することができます。キーが既に存在する場合は、何もしません。
put()
メソッドは、キーが既に存在する場合は値を上書きします。
// マップを生成(マップを変更可能にしたいので、Map.of()は使わない)
Map<String, Integer> fruitsMap = new HashMap<>();
// マップにフルーツの名前と数量を追加
fruitsMap.put("apple", 10);
fruitsMap.put("banana", 20);
fruitsMap.put("orange", 30);
// grapeは存在しないのでマップに追加される
fruitsMap.putIfAbsent("grape", 40);
// appleは存在するのでマップに追加されない(数量は10のまま)
fruitsMap.putIfAbsent("apple", 50);
// マップの内容を表示
fruitsMap.forEach((k, v) -> System.out.println("フルーツ: " + k + ", 数量: " + v));
フルーツ: banana, 数量: 20
フルーツ: orange, 数量: 30
フルーツ: apple, 数量: 10
フルーツ: grape, 数量: 40
マップに値を追加しつつ取得する
追加した値をすぐに取得したい場合は、compute()
メソッドを使います。第1引数にはキーを指定します。第2引数には、キーと現在の値を引数に取り、新しい値を返すラムダ式を指定します。
// マップを生成(マップを変更可能にしたいので、Map.of()は使わない)
Map<String, Integer> fruitsMap = new HashMap<>();
// マップにフルーツの名前と数量を追加
fruitsMap.put("apple", 10);
fruitsMap.put("banana", 20);
fruitsMap.put("orange", 30);
// grapeは存在しないのでマップに追加される
// k = "grape", v = null
int grapeCount = fruitsMap.compute("grape", (k, v) -> 40);
System.out.println("ブドウの数量: " + grapeCount);
// appleは存在するので値が50に更新される
// k = "apple", v = 10
int appleCount = fruitsMap.compute("apple", (k, v) -> 50);
System.out.println("リンゴの数量: " + appleCount);
ブドウの数量: 40
リンゴの数量: 50
キーが存在しない場合のみ、マップに値を追加しつつ取得する
computeIfAbsent()
メソッドを使います。第1引数にはキーを指定します。第2引数には、キーを引数に取り、新しい値を返すラムダ式を指定します。
// マップを生成(マップを変更可能にしたいので、Map.of()は使わない)
Map<String, Integer> fruitsMap = new HashMap<>();
// マップにフルーツの名前と数量を追加
fruitsMap.put("apple", 10);
fruitsMap.put("banana", 20);
fruitsMap.put("orange", 30);
// grapeは存在しないのでマップに追加される
int grapeCount = fruitsMap.computeIfAbsent("grape", k -> 40);
System.out.println("ブドウの数量: " + grapeCount);
// appleは存在するのでマップは更新されず、現在の値10が返る
int appleCount = fruitsMap.computeIfAbsent("apple", k -> 50);
System.out.println("リンゴの数量: " + appleCount);
ブドウの数量: 40
リンゴの数量: 10
キーが存在する場合のみ、マップに値を追加しつつ取得する
computeIfPresent()
メソッドもあります。
合わせて読みたい
Discussion