Menggabungkan Dua Peta dengan Java 8

1. Perkenalan

Dalam tutorial singkat ini, kami akan mendemonstrasikan cara menggabungkan dua peta menggunakan kapabilitas Java 8 .

Untuk lebih spesifik, kami akan memeriksa berbagai skenario penggabungan termasuk peta yang memiliki entri duplikat.

2. Inisialisasi

Sebagai permulaan, mari kita tentukan dua contoh Map :

private static Map map1 = new HashMap(); private static Map map2 = new HashMap();

Kelas Karyawan terlihat seperti ini:

public class Employee {       private Long id;     private String name;       // constructor, getters, setters }

Kemudian, kita dapat memasukkan beberapa data ke dalam instance Map :

Employee employee1 = new Employee(1L, "Henry"); map1.put(employee1.getName(), employee1); Employee employee2 = new Employee(22L, "Annie"); map1.put(employee2.getName(), employee2); Employee employee3 = new Employee(8L, "John"); map1.put(employee3.getName(), employee3); Employee employee4 = new Employee(2L, "George"); map2.put(employee4.getName(), employee4); Employee employee5 = new Employee(3L, "Henry"); map2.put(employee5.getName(), employee5);

Catatan, bahwa kita memiliki kunci identik untuk employee1 dan employee5 entri dalam peta kami yang akan kita gunakan nanti.

3. Map.merge ()

Java 8 menambahkan fungsi merge () baru ke dalam antarmuka java.util.Map .

Berikut adalah cara kerja fungsi merge () : Jika kunci yang ditentukan belum dikaitkan dengan nilai atau nilainya null, ia akan mengaitkan kunci dengan nilai yang diberikan.

Jika tidak, itu menggantikan nilai dengan hasil dari fungsi pemetaan ulang yang diberikan. Jika hasil dari fungsi pemetaan ulang adalah nol, itu menghapus hasilnya.

Pertama, mari buat HashMap baru dengan menyalin semua entri dari map1 :

Map map3 = new HashMap(map1);

Selanjutnya, mari kita perkenalkan fungsi merge () bersama dengan aturan penggabungan:

map3.merge(key, value, (v1, v2) -> new Employee(v1.getId(),v2.getName())

Akhirnya, kita akan mengulang map2 dan menggabungkan entri ke map3 :

map2.forEach( (key, value) -> map3.merge(key, value, (v1, v2) -> new Employee(v1.getId(),v2.getName())));

Mari jalankan program dan cetak konten map3 :

John=Employee{id=8, name="John"} Annie=Employee{id=22, name="Annie"} George=Employee{id=2, name="George"} Henry=Employee{id=1, name="Henry"}

Hasilnya, Peta gabungan kami memiliki semua elemen dari entri HashMap sebelumnya . Entri dengan kunci duplikat telah digabungkan menjadi satu entri .

Juga, kita perhatikan bahwa objek Employee dari entri terakhir memiliki id dari map1 , dan nilai diambil dari map2 .

Ini karena aturan yang kami tentukan dalam fungsi penggabungan kami:

(v1, v2) -> new Employee(v1.getId(), v2.getName())

4. Stream.concat ()

The Streaming API di Jawa 8 juga dapat memberikan solusi mudah untuk masalah kita. Pertama, kita perlu menggabungkan instance Map kita menjadi satu Stream . Itulah tepatnya yang dilakukan operasi Stream.concat () :

Stream combined = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream());

Di sini kita melewatkan set entri peta sebagai parameter. Selanjutnya, kita perlu mengumpulkan hasil kita ke dalam Peta baru . Untuk itu kita bisa menggunakan Collectors.toMap () :

Map result = combined.collect( Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Hasilnya, kolektor akan menggunakan kunci dan nilai yang ada dari peta kita. Tetapi solusi ini masih jauh dari sempurna. Segera setelah kolektor kita bertemu entri dengan kunci duplikat, itu akan memunculkan IllegalStateException .

Untuk menangani masalah ini, kami cukup menambahkan parameter lambda "penggabungan" ketiga ke dalam kolektor kami:

(value1, value2) -> new Employee(value2.getId(), value1.getName())

Ini akan menggunakan ekspresi lambda setiap kali kunci duplikat terdeteksi.

Akhirnya, menyatukan semuanya:

Map result = Stream.concat(map1.entrySet().stream(), map2.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (value1, value2) -> new Employee(value2.getId(), value1.getName())));

Terakhir, mari kita jalankan kodenya dan lihat hasilnya:

George=Employee{id=2, name="George"} John=Employee{id=8, name="John"} Annie=Employee{id=22, name="Annie"} Henry=Employee{id=3, name="Henry"}

Seperti yang kita lihat, entri duplikat dengan kunci "Henry" digabungkan menjadi pasangan nilai kunci baru di mana id Karyawan baru diambil dari map2 dan nilai dari map1 .

5. Stream.of ()

Untuk terus menggunakan Stream API, kita dapat mengubah contoh Peta kita menjadi aliran terpadu dengan bantuan Stream.of () .

Di sini kita tidak perlu membuat koleksi tambahan untuk bekerja dengan aliran:

Map map3 = Stream.of(map1, map2) .flatMap(map -> map.entrySet().stream()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> new Employee(v1.getId(), v2.getName())));

Pertama, kami mengubah map1 dan map2 menjadi satu aliran . Selanjutnya, kami mengubah aliran menjadi peta. Seperti yang bisa kita lihat, argumen terakhir toMap () adalah fungsi penggabungan. Ini memecahkan masalah kunci duplikat dengan memilih bidang id dari entri v1 , dan nama dari v2 .

Contoh map3 dicetak setelah menjalankan program:

George=Employee{id=2, name="George"} John=Employee{id=8, name="John"} Annie=Employee{id=22, name="Annie"} Henry=Employee{id=1, name="Henry"}

6. Streaming Sederhana

Selain itu, kita bisa menggunakan pipeline stream () untuk mengumpulkan entri peta kita. Potongan kode di bawah ini menunjukkan bagaimana menambahkan entri dari map2 dan map1 dengan mengabaikan entri duplikat:

Map map3 = map2.entrySet() .stream() .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> new Employee(v1.getId(), v2.getName()), () -> new HashMap(map1)));

Seperti yang kami harapkan, hasil setelah penggabungan adalah:

{John=Employee{id=8, name="John"}, Annie=Employee{id=22, name="Annie"}, George=Employee{id=2, name="George"}, Henry=Employee{id=1, name="Henry"}}

7. StreamEx

In addition to solutions that are provided by the JDK, we can also use the popular StreamEx library.

Simply put, StreamEx is an enhancement for the Stream API and provides many additional useful methods. We'll use an EntryStream instance to operate on key-value pairs:

Map map3 = EntryStream.of(map1) .append(EntryStream.of(map2)) .toMap((e1, e2) -> e1);

The idea is to merge the streams of our maps into one. Then we collect the entries into the new map3 instance. Important to mention, the (e1, e2) -> e1 expression as it helps to define the rule for dealing with the duplicate keys. Without it, our code will throw an IllegalStateException.

And now, the results:

{George=Employee{id=2, name="George"}, John=Employee{id=8, name="John"}, Annie=Employee{id=22, name="Annie"}, Henry=Employee{id=1, name="Henry"}}

8. Summary

Dalam artikel singkat ini, kami mempelajari berbagai cara menggabungkan peta di Java 8. Lebih khusus lagi, kami menggunakan Map.merge (), Stream API, library StreamEx .

Seperti biasa, kode yang digunakan selama diskusi dapat ditemukan di GitHub.