1. Gambaran keseluruhan
Dalam tutorial ini, kami akan menerangkan cara menapis dan mengubah koleksi dengan Jambu Batu .
Kami akan menapis menggunakan Predicates, mengubah menggunakan Fungsi yang disediakan oleh perpustakaan dan akhirnya, kami akan melihat bagaimana menggabungkan penapisan dan transformasi.
2. Tapis Koleksi
Mari kita mulakan dengan contoh mudah menapis koleksi . Kami akan menggunakan Predicate out of the box yang disediakan oleh perpustakaan dan dibina melalui kelas utiliti Predicates :
@Test public void whenFilterWithIterables_thenFiltered() { List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Iterable result = Iterables.filter(names, Predicates.containsPattern("a")); assertThat(result, containsInAnyOrder("Jane", "Adam")); }
Seperti yang anda lihat, kami menyaring Senarai nama untuk mendapatkan hanya nama yang mengandungi watak "a" - dan kami menggunakan Iterables.filter () untuk melakukannya.
Sebagai alternatif, kita dapat memanfaatkan API Collections2.filter () dengan baik juga:
@Test public void whenFilterWithCollections2_thenFiltered() { List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = Collections2.filter(names, Predicates.containsPattern("a")); assertEquals(2, result.size()); assertThat(result, containsInAnyOrder("Jane", "Adam")); result.add("anna"); assertEquals(5, names.size()); }
Beberapa perkara yang perlu diperhatikan di sini - pertama, output dari Collections.filter () adalah paparan langsung koleksi asal - perubahan pada satu akan dapat dilihat pada yang lain.
Penting juga untuk difahami bahawa sekarang, hasilnya dikekang oleh predikat - jika kita menambahkan elemen yang tidak memenuhi Predicate tersebut , IllegalArgumentException akan dilemparkan:
@Test(expected = IllegalArgumentException.class) public void givenFilteredCollection_whenAddingInvalidElement_thenException() { List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = Collections2.filter(names, Predicates.containsPattern("a")); result.add("elvis"); }
3. Tulis Predikat Penapis Tersuai
Seterusnya - mari tulis Predicate kita sendiri dan bukannya menggunakan yang disediakan oleh perpustakaan. Dalam contoh berikut - kami akan menentukan predikat yang hanya mendapat nama yang dimulai dengan "A" atau "J":
@Test public void whenFilterCollectionWithCustomPredicate_thenFiltered() { Predicate predicate = new Predicate() { @Override public boolean apply(String input) return input.startsWith("A") }; List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = Collections2.filter(names, predicate); assertEquals(3, result.size()); assertThat(result, containsInAnyOrder("John", "Jane", "Adam")); }
4. Menggabungkan Predikat Berbilang
Kita boleh Menggabungkan Pelbagai Predikat menggunakan Predicates.or () dan Predicates.and () .
Dalam contoh berikut - kami menyaring Senarai nama untuk mendapatkan nama yang dimulai dengan "J" atau tidak mengandung "a":
@Test public void whenFilterUsingMultiplePredicates_thenFiltered() { List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = Collections2.filter(names, Predicates.or(Predicates.containsPattern("J"), Predicates.not(Predicates.containsPattern("a")))); assertEquals(3, result.size()); assertThat(result, containsInAnyOrder("John", "Jane", "Tom")); }
5. Keluarkan Null Nilai Semasa Menyaring Koleksi
Kita dapat membersihkan nilai nol dari koleksi dengan menyaringnya dengan Predicates.notNull () seperti dalam contoh berikut:
@Test public void whenRemoveNullFromCollection_thenRemoved() { List names = Lists.newArrayList("John", null, "Jane", null, "Adam", "Tom"); Collection result = Collections2.filter(names, Predicates.notNull()); assertEquals(4, result.size()); assertThat(result, containsInAnyOrder("John", "Jane", "Adam", "Tom")); }
6. Periksa Jika Semua Elemen dalam Koleksi Sesuai dengan Keadaan
Seterusnya, mari kita periksa sama ada semua elemen dalam Koleksi sesuai dengan keadaan tertentu. Kami akan menggunakan Iterables.all () untuk memeriksa apakah semua nama berisi "n" atau "m", maka kami akan memeriksa apakah semua elemen mengandung "a":
@Test public void whenCheckingIfAllElementsMatchACondition_thenCorrect() m")); assertTrue(result); result = Iterables.all(names, Predicates.containsPattern("a")); assertFalse(result);
7. Transformasi Koleksi
Sekarang - mari kita lihat bagaimana mengubah koleksi menggunakan Guava Function . Dalam contoh berikut - kita mengubah Senarai nama-nama kepada Senarai daripada Integer (panjang nama) dengan Iterables.transform () :
@Test public void whenTransformWithIterables_thenTransformed() { Function function = new Function() { @Override public Integer apply(String input) { return input.length(); } }; List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Iterable result = Iterables.transform(names, function); assertThat(result, contains(4, 4, 4, 3)); }
Kami juga dapat menggunakan API Collections2.transform () seperti dalam contoh berikut:
@Test public void whenTransformWithCollections2_thenTransformed() { Function func = new Function(){ @Override public Integer apply(String input) { return input.length(); } }; List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = Collections2.transform(names, func); assertEquals(4, result.size()); assertThat(result, contains(4, 4, 4, 3)); result.remove(3); assertEquals(3, names.size()); }
Perhatikan bahawa output Collections.transform () adalah paparan langsung dari Koleksi asal - perubahan pada satu mempengaruhi yang lain.
Dan - sama seperti sebelumnya - jika kita cuba menambahkan elemen pada Koleksi output , UnsupportedOperationException akan dilemparkan.
8. Buat Fungsi dari Predicate
Kita juga boleh membuat Fungsi dari Predicate menggunakan Functions.fromPredicate () . Ini tentu saja akan menjadi fungsi yang mengubah input ke Boolean , sesuai dengan keadaan predikat.
Dalam contoh berikut, kita mengubah Senarai nama menjadi senarai booleans di mana setiap elemen mewakili jika nama itu mengandungi "m"
@Test public void whenCreatingAFunctionFromAPredicate_thenCorrect() { List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = Collections2.transform(names, Functions.forPredicate(Predicates.containsPattern("m"))); assertEquals(4, result.size()); assertThat(result, contains(false, false, true, true)); }
9. Komposisi Dua Fungsi
Seterusnya - mari kita lihat bagaimana mengubah Koleksi menggunakan Fungsi tersusun .
Functions.compose () mengembalikan Komposisi Dua Fungsi kerana menerapkan Fungsi kedua pada output Fungsi pertama .
Dalam contoh berikut - Fungsi pertama mengubah nama menjadi panjangnya, kemudian Fungsi kedua mengubah panjang menjadi nilai boolean yang mewakili jika panjang nama itu sama rata:
@Test public void whenTransformingUsingComposedFunction_thenTransformed() { Function f1 = new Function(){ @Override public Integer apply(String input) { return input.length(); } }; Function f2 = new Function(){ @Override public Boolean apply(Integer input) { return input % 2 == 0; } }; List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = Collections2.transform(names, Functions.compose(f2, f1)); assertEquals(4, result.size()); assertThat(result, contains(true, true, true, false)); }
10. Gabungkan Penapisan dan Transformasi
And now – let's see another cool API that Guava has – one that will actually allow us to chain filtering and transforming together – the FluentIterable.
In the following example – we filter the List of names then transform it using FluentIterable:
@Test public void whenFilteringAndTransformingCollection_thenCorrect() { Predicate predicate = new Predicate() { @Override public boolean apply(String input) }; Function func = new Function(){ @Override public Integer apply(String input) { return input.length(); } }; List names = Lists.newArrayList("John", "Jane", "Adam", "Tom"); Collection result = FluentIterable.from(names) .filter(predicate) .transform(func) .toList(); assertEquals(2, result.size()); assertThat(result, containsInAnyOrder(4, 3)); }
It is worth mentioning that, in some cases, the imperative version is more readable and should be preferred to the functional approach.
11. Conclusion
Finally, we learned how to filter and transform collections using Guava. We used the Collections2.filter() and Iterables.filter() APIs for filtering, as well as Collections2.transform() and Iterables.transform() to transform collections.
Akhirnya, kami melihat API FluentIterable fasih yang sangat menarik untuk menggabungkan penapisan dan transformasi.
Pelaksanaan semua contoh dan coretan kod ini boleh didapati di projek GitHub - ini adalah projek berasaskan Maven, jadi mudah diimport dan dijalankan sebagaimana adanya.