Memfilter Koleksi Java dengan Daftar

1. Ikhtisar

Memfilter Koleksi menurut Daftar adalah skenario logika bisnis yang umum. Ada banyak cara untuk mencapai ini. Namun, beberapa dapat menyebabkan solusi berkinerja buruk jika tidak dilakukan dengan benar.

Dalam tutorial ini, kita akan membandingkan beberapa implementasi pemfilteran dan membahas kelebihan dan kekurangannya .

2. Menggunakan For-Each Loop

Kami akan mulai dengan sintaks paling klasik, untuk setiap loop.

Untuk ini dan semua contoh lainnya di artikel ini, kami akan menggunakan kelas berikut:

public class Employee { private Integer employeeNumber; private String name; private Integer departmentId; //Standard constructor, getters and setters. }

Kami juga akan menggunakan metode berikut untuk semua contoh, demi kesederhanaan:

private List buildEmployeeList() { return Arrays.asList( new Employee(1, "Mike", 1), new Employee(2, "John", 1), new Employee(3, "Mary", 1), new Employee(4, "Joe", 2), new Employee(5, "Nicole", 2), new Employee(6, "Alice", 2), new Employee(7, "Bob", 3), new Employee(8, "Scarlett", 3)); } private List employeeNameFilter() { return Arrays.asList("Alice", "Mike", "Bob"); }

Untuk contoh kami, kami akan memfilter daftar Karyawan pertama berdasarkan daftar kedua dengan nama Karyawan untuk hanya menemukan Karyawan dengan nama spesifik tersebut.

Sekarang, mari kita lihat pendekatan tradisional - mengulang kedua daftar untuk mencari kecocokan:

@Test public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingForEachLoop() { List filteredList = new ArrayList(); List originalList = buildEmployeeList(); List nameFilter = employeeNameFilter(); for (Employee employee : originalList) { for (String name : nameFilter) { if (employee.getName().equals(name)) { filteredList.add(employee); // break; } } } assertThat(filteredList.size(), is(nameFilter.size())); }

Ini adalah sintaks yang sederhana, tetapi cukup bertele-tele, dan sebenarnya sangat tidak efisien. Sederhananya, ini mengulangi produk Cartesian dari dua set untuk mendapatkan jawaban kita.

Bahkan menambahkan jeda untuk keluar lebih awal masih akan mengulangi urutan yang sama seperti produk Cartesian dalam kasus rata-rata.

Jika kita menyebut ukuran daftar karyawan n, maka nameFilter akan berada di urutan seperti besar, memberikan kita sebuah O (n2) klasifikasi.

3. Menggunakan Streams dan List # berisi

Kami sekarang akan merefaktor metode sebelumnya dengan menggunakan lambda untuk menyederhanakan sintaks dan meningkatkan keterbacaan . Mari juga gunakan metode List # contains sebagai filter lambda :

@Test public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambda() { List filteredList; List originalList = buildEmployeeList(); List nameFilter = employeeNameFilter(); filteredList = originalList.stream() .filter(employee -> nameFilter.contains(employee.getName())) .collect(Collectors.toList()); assertThat(filteredList.size(), is(nameFilter.size())); }

Dengan menggunakan API Stream , keterbacaan telah sangat ditingkatkan, tetapi kode kami tetap tidak efisien seperti metode sebelumnya karena masih melakukan iterasi melalui produk Cartesian secara internal . Jadi, kami memiliki klasifikasi O (n2) yang sama .

4. Menggunakan Stream dengan HashSet

Untuk meningkatkan kinerja, kita harus menggunakan metode HashSet # berisi . Metode ini berbeda dari List # contains karena melakukan pencarian kode hash , memberi kita jumlah operasi waktu konstan:

@Test public void givenEmployeeList_andNameFilterList_thenObtainFilteredEmployeeList_usingLambdaAndHashSet() { List filteredList; List originalList = buildEmployeeList(); Set nameFilterSet = employeeNameFilter().stream().collect(Collectors.toSet()); filteredList = originalList.stream() .filter(employee -> nameFilterSet.contains(employee.getName())) .collect(Collectors.toList()); assertThat(filteredList.size(), is(nameFilterSet.size())); }

Dengan menggunakan HashSet, efisiensi kode kami telah meningkat pesat tanpa memengaruhi keterbacaan. Karena HashSet # berisi berjalan dalam waktu konstan, kami telah meningkatkan klasifikasi kami menjadi O (n).

5. Kesimpulan

Dalam tutorial singkat ini, kita belajar bagaimana memfilter Koleksi berdasarkan Daftar nilai dan kekurangan menggunakan metode yang kelihatannya paling mudah.

Kita harus selalu mempertimbangkan efisiensi karena kode kita mungkin akan berjalan dalam kumpulan data yang sangat besar, dan masalah kinerja dapat menimbulkan konsekuensi bencana di lingkungan seperti itu.

Semua kode yang disajikan dalam artikel ini tersedia di GitHub.