参考にした情報 Merging Two Maps with Java このなかの、Stream を結合する方法を参考にしました。入力は2つの Map 、出力は List です。
Java
1public static List<After> merge(Map<Parent,List<ChildA>> mapA, Map<Parent,List<ChildB>> mapB) {
2 return Stream.concat(
3 mapA.entrySet().stream().map(e -> new After(e.getKey(),e.getValue(),null)),
4 mapB.entrySet().stream().map(e -> new After(e.getKey(),null,e.getValue()))
5 ).collect(Collectors.groupingBy(e -> e.getParent()))
6 .values().stream()
7 .map(l -> l.stream().reduce(new After(),(a,b)-> new After(a,b)))
8 .collect(Collectors.toList());
9}
Afterにコンストラクタが必要なので追加しました。Parentの取得メソッドも追加。(フィールドが private なので)
Java
1class After {
2 private Parent parent;
3 private List<ChildA> childA;
4 private List<ChildB> childB;
5
6 public After(Parent parent, List<ChildA> childA, List<ChildB> childB) {
7 this.parent = parent;
8 this.childA = (childA == null) ? new ArrayList<>() : childA;
9 this.childB = (childB == null) ? new ArrayList<>() : childB;
10 }
11 public After(After a, After b) { // reduce マージ用コンストラクタ
12 this((a.parent!=null)?a.parent:b.parent,a.childA,a.childB);
13 this.childA.addAll(b.childA);
14 this.childB.addAll(b.childB);
15 }
16 public After() { this(null,null,null); } // reduce 初期値
17
18 public Parent getParent() { return this.parent; } // Parent の取得
19
20}
POJO をキーにするということなので、Parentの equals()/hahsCode() をオーバーライドしました。自作オブジェクトを HashMap に格納するには必要です。equals()/hahsCode() に必要なフィールドは、final 変更できません。変更すると HashMap から取り出せなくなるから。意味がわからなければ、ご自分で調べてください。
Java
1class Parent {
2 private final Integer pk1; // parentのpk
3 private final String pk2; // parentのpk
4
5 public Parent(Integer pk1, String pk2) {
6 this.pk1 = pk1;
7 this.pk2 = pk2;
8 }
9
10 @Override
11 public boolean equals(Object obj) {
12 if (obj == this) {
13 return true;
14 }
15 if (!(obj instanceof Parent)) {
16 return false;
17 }
18 Parent right = (Parent)obj;
19 if (!this.pk1.equals(right.pk1)) {
20 return false;
21 }
22 if (!this.pk2.equals(right.pk2)) {
23 eturn false;
24 }
25 return true;
26 }
27
28 @Override
29 public int hashCode() {
30 return pk1.hashCode() + pk2.hashCode();
31 }
32
33}
After のマージコンストラクター (2019-05-08)
Map.merge()を使うと map に格納する型が合わず型変換が必要になる。After のコンストラクターにマージ機能を持たせるほうが凝集度が高くなるし、畳み込みにより2件以上のマージができると判断。
キーオブジェクトの equals()/hashCode()、immutable (2019-05-08)
参考書は『Effective Java』 第1版〜第3版 のどれでもよい、読んでみてください。
Mapのキーについての議論
HashMap/Setにまつわる2つの事
Immutable objects and hashmap keys
Java の基礎として知ておくべき。調べたうえで疑問が残るなら、別の質問をポストしてください。
hashCode() を Effective Java にあわせる (2019-05-09)
J. Broch さんはこれがベストではないと断っていますが、Effective Java にあわせます。
Java
1 @Override
2 public int hashCode() {
3 int result = 17;
4 result = result * 31 + pk1.hashCode();
5 result = result * 31 + pk2.hashCode();
6 return result;
7 }
pk1、pk2 はプライマリキーなので null になりえないことが前提です。また final な変数ゆえに1度だけ計算してキャッシュすることもできます。