Di Java 8, Anda bisa menggunakan referensi metode untuk memfilter aliran, misalnya:
Stream<String> s = ...;
long emptyStrings = s.filter(String::isEmpty).count();
Apakah ada cara untuk membuat referensi metode yang merupakan negasi dari yang sudah ada, yaitu sesuatu seperti:
long nonEmptyStrings = s.filter(not(String::isEmpty)).count();
Saya dapat membuat not
metode seperti di bawah ini tetapi saya bertanya-tanya apakah JDK menawarkan sesuatu yang serupa.
static <T> Predicate<T> not(Predicate<T> p) { return o -> !p.test(o); }
Predicate.not(Predicate)
metode statis . Tapi masalah itu masih terbuka sehingga kita akan melihat ini paling awal di Java 12 (jika pernah).Jawaban:
Predicate.not( … )
java-11menawarkan metode baru. Predikat # tidak
Jadi Anda dapat meniadakan referensi metode:
sumber
Saya berencana mengimpor statis berikut ini untuk memungkinkan referensi metode yang akan digunakan inline:
misalnya
Pembaruan : Mulai dari Java-11, JDK juga menawarkan solusi serupa .
sumber
Ada cara untuk membuat referensi metode yang merupakan kebalikan dari referensi metode saat ini. Lihat jawaban @ vlasec di bawah ini yang menunjukkan bagaimana dengan secara eksplisit melemparkan referensi metode ke a
Predicate
dan kemudian mengubahnya menggunakannegate
fungsi. Itu adalah salah satu cara di antara beberapa cara lain yang tidak terlalu merepotkan untuk melakukannya.Kebalikan dari ini:
Apakah ini:
atau ini:
Secara pribadi, saya lebih suka teknik nanti karena saya merasa lebih jelas untuk membaca
it -> !it.isEmpty()
daripada pemeran verbal panjang dan kemudian meniadakan.Anda juga bisa membuat predikat dan menggunakannya kembali:
Atau, jika memiliki koleksi atau array, cukup gunakan for-loop yang sederhana, memiliki lebih sedikit overhead, dan * mungkin ** lebih cepat:
* Jika Anda ingin tahu apa yang lebih cepat, maka gunakan JMH http://openjdk.java.net/projects/code-tools/jmh , dan hindari kode benchmark tangan kecuali menghindari semua optimasi JVM - lihat Java 8: kinerja Streams vs Koleksi
** Saya mendapatkan kritik karena menyarankan bahwa teknik for-loop lebih cepat. Ini menghilangkan pembuatan aliran, menghilangkan menggunakan pemanggilan metode lain (fungsi negatif untuk predikat), dan menghilangkan daftar / penghitung akumulator sementara. Jadi beberapa hal yang disimpan oleh konstruk terakhir yang mungkin membuatnya lebih cepat.
Saya pikir itu lebih sederhana dan lebih baik, meskipun tidak lebih cepat. Jika pekerjaan itu membutuhkan palu dan paku, jangan bawa gergaji dan lem! Saya tahu beberapa dari Anda mempermasalahkan hal itu.
wish-list: Saya ingin melihat
Stream
fungsi Java berkembang sedikit sekarang karena pengguna Java lebih mengenalnya. Misalnya, metode 'hitung' di Stream dapat menerimaPredicate
sehingga ini dapat dilakukan secara langsung seperti ini:sumber
Predicate.negate(String::isEmpty);
tanpa pengecoran rumit.Predicate
memiliki metodeand
,or
dannegate
.Namun,
String::isEmpty
bukanPredicate
, itu hanyaString -> Boolean
lambda dan itu masih bisa menjadi apa saja, misalnyaFunction<String, Boolean>
. Jenis inferensi inilah yang perlu terjadi terlebih dahulu. Thefilter
Metode menyimpulkan ketik secara implisit . Tetapi jika Anda meniadakannya sebelum meneruskannya sebagai argumen, itu tidak lagi terjadi. Seperti @axtavt sebutkan, inferensi eksplisit dapat digunakan sebagai cara yang jelek:Ada cara lain yang disarankan dalam jawaban lain, dengan
not
metode statis dan lambda kemungkinan besar menjadi ide terbaik. Ini menyimpulkan bagian dr .Namun, jika Anda ingin lebih memahami inferensi tipe lambda, saya ingin menjelaskannya sedikit lebih mendalam, menggunakan contoh. Lihat ini dan coba cari tahu apa yang terjadi:
Predicate
keObject
- konyol tapi validPredicate
keFunction
, itu tidak lagi tentang inferensitest
yang ditentukan oleh lambda-nyaInteger
tidak punyaisEmpty
metodeString::isEmpty
metode statis denganInteger
argumenSaya harap ini membantu mendapatkan lebih banyak wawasan tentang cara kerja kesimpulan tipe.
sumber
Membangun jawaban dan pengalaman pribadi orang lain:
sumber
::
referensi fungsional seperti yang mungkin diinginkan (String::isEmpty.negate()
), tetapi jika Anda menetapkan variabel terlebih dahulu (atau dilemparkan ke yangPredicate<String>
pertama), itu berfungsi. Saya pikir lambda!
akan lebih mudah dibaca dalam banyak kasus, tetapi sangat membantu untuk mengetahui apa yang bisa dan tidak bisa dikompilasi.Pilihan lain adalah memanfaatkan lambda casting dalam konteks yang tidak ambigu menjadi satu kelas:
... dan kemudian impor statis kelas utilitas:
sumber
Bukankah
Predicate#negate
seharusnya apa yang Anda cari?sumber
Predicate
pertama.String::isEmpty()
untukPredicate<String>
sebelum - itu sangat jelek.Predicate<String> p = (Predicate<String>) String::isEmpty;
danp.negate()
.s -> !s.isEmpty()
dalam kasus itu!Dalam hal ini Anda dapat menggunakan
org.apache.commons.lang3.StringUtils
dan melakukannyasumber
String::isEmpty
sebagai contoh. Ini masih merupakan informasi yang relevan jika Anda memiliki kasus penggunaan ini, tetapi jika hanya menjawab kasus penggunaan String, maka itu tidak boleh diterima.Saya telah menulis kelas utilitas lengkap (terinspirasi oleh proposal Askar) yang dapat mengambil ekspresi Java 8 lambda dan mengubahnya (jika berlaku) menjadi standar apa pun yang diketikkan Java 8 lambda yang ditentukan dalam paket
java.util.function
. Misalnya Anda dapat melakukan:asPredicate(String::isEmpty).negate()
asBiPredicate(String::equals).negate()
Karena akan ada banyak ambiguitas jika semua metode statis akan dinamai adil
as()
, saya memilih untuk memanggil metode "sebagai" diikuti oleh jenis yang dikembalikan. Ini memberi kita kendali penuh atas interpretasi lambda. Di bawah ini adalah bagian pertama dari kelas utilitas (agak besar) mengungkapkan pola yang digunakan.Lihatlah kelas lengkapnya di sini (di intisari).
sumber
Anda dapat menggunakan Predikat dari Eclipse Collections
Jika Anda tidak dapat mengubah string dari
List
:Jika Anda hanya membutuhkan negasi,
String.isEmpty()
Anda juga dapat menggunakannyaStringPredicates.notEmpty()
.Catatan: Saya adalah kontributor untuk Eclipse Collections.
sumber
Anda bisa melakukannya selama ini
emptyStrings = s.filter(s->!s.isEmpty()).count();
sumber
Jika Anda menggunakan Spring Boot (2.0.0+) Anda dapat menggunakan:
Yang tidak:
return (str != null && !str.isEmpty());
Jadi itu akan memiliki efek negasi yang diperlukan untuk
isEmpty
sumber