【Java】Map使用時、keySetでSetへのaddAllは注意!?

2つのMap変数のkeyを1発で重複値なく保持したい場合、ListではなくSetを使いますよね?
ただ実際実行してみると、問題があったのですよ…

【参考に】
・Setは重複要素を保持しない。
・Listは重複要素を保持する。


Set変数に対して、順番に「add」するのであれば問題ないようなのですが、「addAll」だと「UnsupportedOperationException」が発生してしまうのです

例の実装です

Map<Integer, List<String>> testMap1 = new HashMap<>();
Map<Integer, List<String>> testMap2 = new HashMap<>();

List<String> list1 = new ArrayList<String>(Arrays.asList("01", "02", "03"));
List<String> list2 = new ArrayList<String>(Arrays.asList("04", "05", "06"));
List<String> list3 = new ArrayList<String>(Arrays.asList("07", "08", "09"));

testMap1.put(1, list1);
testMap2.put(1, list2);
testMap2.put(2, list3);

// testMap1からkeyを全件取得
Set<Integer> numberList1 = testMap1.keySet();

// testMap2からkeyを全件取得(重複データである「1」は追加されない想定)
numberList1.addAll(testMap2.keySet());  // ← ここで「UnsupportedOperationException」発生

for (Integer number : numberList1) {
	System.out.println(number);
}

はい、「その処理はできないよ!」って感じですね
※ なんでかは原因は不明(笑)

今回の事案の場合の2通り解決案を提示したいと思います

【解決案1】
Listで保持してから、重複を削除します

Map<Integer, List<String>> testMap1 = new HashMap<>();
Map<Integer, List<String>> testMap2 = new HashMap<>();

List<String> list1 = new ArrayList<String>(Arrays.asList("01", "02", "03"));
List<String> list2 = new ArrayList<String>(Arrays.asList("04", "05", "06"));
List<String> list3 = new ArrayList<String>(Arrays.asList("07", "08", "09"));

testMap1.put(1, list1);
testMap2.put(1, list2);
testMap2.put(2, list3);

// testMap1からkeyを全件取得し、List型に格納
List<Integer> numberList1 = new ArrayList<>(testMap1.keySet());

// testMap2からkeyを全件取得し、List型に格納(「1」が2件ある状態)
numberList1.addAll(new ArrayList<>(testMap2.keySet()));

// 「stream().distinct()」関数を使用し、重複データ(「1」)を削除する。
List<Integer> distinctNumberList1 = 
		numberList1.stream().distinct().collect(Collectors.toList());

for (Integer number : distinctNumberList1) {
	System.out.println(number);
}

// 出力結果
// 1
// 2

【解決案2】
Setを維持でも使う!
順番にaddしていこう作戦

List<String> list1 = new ArrayList<String>(Arrays.asList("01", "02", "03"));
List<String> list2 = new ArrayList<String>(Arrays.asList("04", "05", "06"));
List<String> list3 = new ArrayList<String>(Arrays.asList("07", "08", "09"));

testMap1.put(1, list1);
testMap2.put(1, list2);
testMap2.put(2, list3);

// testMap1からkeyを全件取得
Set<Integer> mergeNumberSet = testMap1.keySet();

// testMap2からkeyを全件取得し、順番にaddしていく
for (Integer number : testMap2.keySet()) {
	mergeNumberSet.add(number);
}

for (Integer mergeNumber : mergeNumberSet) {
	System.out.println(mergeNumber);
}
// 出力結果
// 1
// 2

私的にはstreamのほうがきれいに見えますし、行数が2行ということでオススメさせていただきます
(個人的にfor文がいっぱいあるのは好きでない…www)

他に何か実装案があるという方がいらっしゃいましたら、コメント欄にメッセージを頂けましたら幸いです

ではっ

是非フォローしてください

最新の情報をお伝えします

コメントを残す