Menggabungkan Dua Peta dengan Java 8

1. Pengenalan

Dalam tutorial ringkas ini, kami akan menunjukkan bagaimana menggabungkan dua peta menggunakan kemampuan Java 8 .

Untuk lebih spesifik, kami akan mengkaji senario penggabungan yang berbeza termasuk peta yang mempunyai entri pendua.

2. Permulaan

Sebagai permulaan, mari kita tentukan dua contoh Peta :

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

Yang pekerja kelas kelihatan seperti ini:

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

Kemudian, kita dapat memasukkan beberapa data ke dalam contoh Peta :

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);

Nota, bahawa kita mempunyai kunci sama untuk employee1 dan employee5 catatan dalam peta kami yang akan kami gunakan kemudian.

3. Peta.merge ()

Java 8 menambah fungsi gabungan () ke antara muka java.util.Map .

Berikut adalah cara fungsi penggabungan () berfungsi: Sekiranya kunci yang ditentukan belum dikaitkan dengan nilai atau nol, ia mengaitkan kunci dengan nilai yang diberikan.

Jika tidak, ia menggantikan nilai dengan hasil fungsi pemetaan semula yang diberikan. Sekiranya hasil fungsi pemetaan semula adalah nol, ia akan menghilangkan hasilnya.

Pertama, mari kita membina HashMap baru dengan menyalin semua entri dari peta1 :

Map map3 = new HashMap(map1);

Seterusnya, mari kita memperkenalkan fungsi penggabungan () bersama dengan peraturan penggabungan:

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

Akhirnya, kami akan mengulangi peta2 dan menggabungkan entri ke dalam peta3 :

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

Mari jalankan program dan mencetak kandungan peta3 :

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 mempunyai semua elemen dari entri HashMap sebelumnya . Entri dengan kunci pendua telah digabungkan menjadi satu entri .

Juga, kita perhatikan bahawa objek Karyawan dari entri terakhir mempunyai id dari map1 , dan nilai dipilih dari map2 .

Ini kerana peraturan yang kami tetapkan dalam fungsi penggabungan kami:

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

4. Stream.concat ()

The Stream API di Jawa 8 juga boleh menyediakan satu penyelesaian yang mudah kepada masalah kita. Pertama, kita perlu menggabungkan contoh Peta kita menjadi satu Aliran . Itulah yang dilakukan oleh operasi Stream.concat () :

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

Di sini kita lulus set entri peta sebagai parameter. Seterusnya, kita perlu mengumpulkan hasil kita ke Peta baru . Untuk itu kita boleh menggunakan Collectors.toMap () :

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

Hasilnya, pengumpul akan menggunakan kunci dan nilai peta yang ada. Tetapi penyelesaian ini jauh dari sempurna. Sebaik sahaja pengumpul kami memenuhi entri dengan kunci pendua, ia akan membuang IllegalStateException .

Untuk mengatasi masalah ini, kami hanya menambahkan parameter lambda "penggabungan" ketiga ke dalam pemungut kami:

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

Ia akan menggunakan ungkapan lambda setiap kali kunci pendua dikesan.

Akhirnya, menyatukan semua:

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())));

Akhirnya, mari jalankan kod 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 pendua dengan kunci "Henry" digabungkan menjadi pasangan kunci-nilai baru di mana id Pegawai baru diambil dari peta2 dan nilai dari peta1 .

5. Aliran. ()

Untuk terus menggunakan Stream API, kita dapat mengubah contoh Peta kita menjadi aliran bersatu 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, kita mengubah peta1 dan peta2 menjadi satu aliran . Seterusnya, kami menukar aliran menjadi peta. Seperti yang dapat kita lihat, argumen terakhir toMap () adalah fungsi penggabungan. Ini menyelesaikan masalah kunci pendua dengan memilih bidang id dari entri v1 , dan nama dari v2 .

Contoh map3 yang 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. Penstriman Ringkas

Selain itu, kita dapat menggunakan aliran () saluran paip untuk menyusun entri peta kita. Coretan kod di bawah menunjukkan cara menambahkan entri dari peta2 dan peta1 dengan mengabaikan entri pendua:

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 jangkakan, hasil selepas 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 pendek ini, kami mempelajari pelbagai cara menggabungkan peta di Java 8. Lebih khusus lagi, kami menggunakan Map.merge (), Stream API, perpustakaan StreamEx .

Seperti biasa, kod yang digunakan semasa perbincangan boleh didapati di GitHub.