Apakah ada alasannya
Lists.transform()
tapi tidak
Lists.filter()
?
Bagaimana cara memfilter daftar dengan benar? Saya bisa menggunakan
new ArrayList(Collection2.filter())
tentu saja, tapi dengan cara ini tidak ada jaminan bahwa pemesanan saya tetap sama, jika saya mengerti dengan benar.
List.newArrayList(Iterables.filter(...))
, seharusnya dikatakanLists.newArrayList(Iterables.filter(...))
.Jawaban:
Itu tidak diterapkan karena akan mengekspos sejumlah besar metode lambat yang berbahaya, seperti #get (indeks) pada tampilan Daftar yang dikembalikan (mengundang bug kinerja). Dan ListIterator akan menyusahkan untuk diterapkan juga (meskipun saya mengirimkan tambalan bertahun-tahun yang lalu untuk membahasnya).
Karena metode yang diindeks tidak dapat menjadi efisien dalam tampilan Daftar yang difilter, lebih baik menggunakan Iterable yang difilter, yang tidak memilikinya.
sumber
filter
secara konsisten berarti pandangan (bersama dengan perilaku yang menyiratkan) apakah ituIterables.filter
,Sets.filter
dll. KarenaIterables.filter
mudah digabungkan dengancopyOf
apa punImmutableCollection
, saya menemukan ini trade-off desain yang baik (vs datang dengan metode & nama tambahan, sepertifilteredCopy
atau yang lainnya , untuk kombinasi utilitas sederhana).Kamu dapat memakai
Iterables.filter
, yang pasti akan menjaga pemesanan.Perhatikan bahwa dengan membuat daftar baru, Anda akan menyalin elemen (hanya referensi, tentu saja) - jadi ini tidak akan menjadi tampilan langsung ke daftar asli. Membuat tampilan akan sangat sulit - pertimbangkan situasi ini:
Predicate<StringBuilder> predicate = /* predicate returning whether the builder is empty */ List<StringBuilder> builders = Lists.newArrayList(); List<StringBuilder> view = Lists.filter(builders, predicate); for (int i = 0; i < 10000; i++) { builders.add(new StringBuilder()); } builders.get(8000).append("bar"); StringBuilder firstNonEmpty = view.get(0);
Itu harus mengulang seluruh daftar asli, menerapkan filter ke semuanya. Saya kira itu bisa mengharuskan pencocokan predikat tidak berubah selama masa tampilan, tetapi itu tidak akan sepenuhnya memuaskan.
(Ini hanya menebak-nebak, ingat. Mungkin salah satu pengelola Jambu Biji akan menyumbang dengan alasan sebenarnya :)
sumber
Collections2.filter.iterator
hanya panggilanIterables.filter
, jadi hasilnya sama.Iterables.filter
versi hanya untuk kejelasan.view.size()
tempat nanti dalam kode :)Ini tidak benar.
Collections2.filter()
adalah fungsi yang dievaluasi dengan lambat - fungsi ini tidak benar-benar memfilter koleksi Anda sampai Anda mulai mengakses versi yang difilter. Misalnya, jika Anda mengulang versi yang difilter, elemen yang difilter akan keluar dari iterator dengan urutan yang sama seperti koleksi asli Anda (kecuali yang difilter, tentunya).Mungkin Anda berpikir bahwa ia melakukan pemfilteran di depan, lalu membuang hasilnya ke dalam bentuk Koleksi yang sewenang-wenang dan tidak berurutan - ternyata tidak.
Jadi jika Anda menggunakan keluaran dari
Collections2.filter()
sebagai masukan ke daftar baru, maka pesanan asli Anda akan dipertahankan.Menggunakan impor statis (dan
Lists.newArrayList
fungsinya), ini menjadi cukup singkat:Perhatikan bahwa sementara
Collections2.filter
tidak akan bersemangat mengulang koleksi yang mendasarinya,Lists.newArrayList
akan - itu akan mengekstrak semua elemen dari koleksi yang difilter dan menyalinnya ke yang baruArrayList
.sumber
List filteredList = newArrayList(filter(originalList, new Predicate<T>() { @Override public boolean apply(T input) { return (...); } }));
atau ie.List filteredList = newArrayList(filter(originalList, Predicates.notNull()));
Seperti yang disebutkan oleh Jon, Anda dapat menggunakan
Iterables.filter(..)
atauCollections2.filter(..)
dan jika Anda tidak memerlukan tampilan langsung, Anda dapat menggunakanImmutableList.copyOf(Iterables.filter(..))
atauLists.newArrayList( Iterables.filter(..))
dan ya pemesanan akan dipertahankan.Jika Anda benar-benar tertarik dengan why part, Anda dapat mengunjungi https://github.com/google/guava/issues/505 untuk lebih jelasnya.
sumber
Meringkas apa yang dikatakan orang lain, Anda dapat dengan mudah membuat pembungkus umum untuk memfilter daftar:
public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) { return Lists.newArrayList(Iterables.filter(userLists, predicate)); }
sumber