Bab 3 String, Pembanding dan Filter
Beberapa metode yang diperkenalkan oleh JDK sangat membantu untuk menulis kode gaya fungsional. Kita sudah sangat familiar dengan beberapa kelas dan antarmuka di perpustakaan JDK, seperti String. Untuk menghilangkan gaya lama yang biasa kita gunakan, kita harus secara aktif mencari peluang untuk menggunakan metode baru ini. Demikian pula, ketika kita perlu menggunakan kelas dalam anonim dengan hanya satu metode, kita sekarang dapat menggantinya dengan ekspresi lambda, tanpa harus menulisnya rumit seperti sebelumnya.
Dalam bab ini, kita akan menggunakan ekspresi lambda dan referensi metode untuk melintasi string, mengimplementasikan antarmuka Comparator, melihat file dalam direktori, dan memantau perubahan pada file dan direktori. Beberapa metode yang diperkenalkan pada bab sebelumnya akan terus muncul di sini untuk membantu kita menyelesaikan tugas ini dengan lebih baik. Teknik baru yang Anda pelajari akan membantu mengubah kode yang panjang dan membosankan menjadi sesuatu yang ringkas, cepat diterapkan, dan mudah dipelihara.
Ulangi string
Metode chars() adalah metode baru di kelas String, yang merupakan bagian dari antarmuka CharSequence. Ini adalah alat yang sangat berguna jika Anda ingin menelusuri urutan karakter String dengan cepat. Dengan iterator internal ini, kita dapat dengan mudah mengoperasikan setiap karakter dalam string. Coba gunakan untuk memproses string terlebih dahulu. Berikut beberapa cara menggunakan referensi metode.
Copy kode kodenya sebagai berikut:
String terakhir str = "w00t";
str.karakter()
.forEach(ch -> System.out.println(ch));
Metode chars() mengembalikan objek Stream, yang dapat kita gunakan untuk melintasi iterator internal forEach(). Di iterator, kita bisa langsung mengakses karakter yang ada di string. Di bawah ini adalah output dari perulangan string dan mencetak setiap karakter.
Copy kode kodenya sebagai berikut:
119
48
48
116
Ini bukanlah hasil yang kami inginkan. Kita berharap melihat huruf, namun keluarannya berupa angka. Hal ini karena metode chars() mengembalikan aliran bilangan bulat, bukan tipe karakter. Mari kita pahami dulu API ini lalu optimalkan hasil keluarannya.
Pada kode sebelumnya, kita membuat ekspresi lambda sebagai parameter input metode forEach. Itu hanya meneruskan parameter ke metode println(). Karena operasi ini sangat umum, kita dapat menggunakan kompiler Java untuk menyederhanakan kode ini. Sama seperti dalam menggunakan referensi metode di halaman 25, gantilah dengan referensi metode dan biarkan kompiler melakukan perutean parameter untuk kita.
Kita telah melihat cara membuat referensi metode ke metode instan. Misalnya, metode name.toUpperCase(), referensi metodenya adalah String::toUpperCase. Dalam contoh berikut, kami memanggil metode instance yang mereferensikan System.out secara statis. Sisi kiri dari dua titik dua yang direferensikan oleh metode ini dapat berupa nama kelas atau ekspresi. Dengan fleksibilitas ini, kita dapat dengan mudah membuat referensi ke metode println(), seperti di bawah ini.
Copy kode kodenya sebagai berikut:
str.karakter()
.forEach(Sistem.keluar::println);
Seperti yang Anda lihat, kompiler Java dapat menyelesaikan perutean parameter dengan sangat cerdas. Ingatlah bahwa ekspresi lambda dan referensi metode hanya dapat muncul ketika antarmuka fungsional diterima, dan kompiler Java akan menghasilkan metode yang sesuai di sana (Anotasi: Kompiler akan menghasilkan implementasi antarmuka fungsional, yang hanya memiliki satu metode. ). Metode yang kita gunakan sebelumnya mengacu pada String::toUpperCase, dan parameter yang diteruskan ke metode yang dihasilkan pada akhirnya akan menjadi objek target pemanggilan metode, seperti ini: parameter.toUpperCase(). Hal ini karena referensi metode didasarkan pada nama kelas (String). Referensi metode dalam contoh di atas didasarkan pada ekspresi, yang merupakan turunan dari PrintStream dan direferensikan melalui System.out. Karena objek pemanggilan metode sudah ada, compiler Java memutuskan untuk menggunakan parameter dalam metode yang dihasilkan sebagai parameter metode println ini: System.out.println(nama).
(Anotasi: Faktanya, ada dua skenario utama. Referensi metode juga diteruskan. Salah satunya adalah objek yang dilintasi, tentu saja objek target pemanggilan metode, seperti name.toUpperCase, dan yang lainnya digunakan sebagai parameter pemanggilan metode, seperti System.out.println(nama).)
Kode ini jauh lebih sederhana setelah menggunakan referensi metode, namun kita perlu memiliki pemahaman lebih dalam tentang cara kerjanya. Setelah kita terbiasa dengan referensi metode, kita dapat mengetahui sendiri perutean parameter.
Walaupun kode pada contoh ini cukup ringkas, namun outputnya masih kurang memuaskan. Kami berharap melihat huruf tetapi malah muncul angka. Untuk mengatasi masalah ini, mari kita tulis metode untuk menampilkan int sebagai huruf.
Copy kode kodenya sebagai berikut:
pribadi statis void printChar(int aChar) {
Sistem.keluar.println((char)(aChar));
}
Menggunakan referensi metode dapat dengan mudah mengoptimalkan hasil keluaran.
Copy kode kodenya sebagai berikut:
str.karakter()
.forEach(IterateString::printChar);
Sekarang, meskipun hasil yang dikembalikan oleh chars() adalah int, itu tidak masalah. Saat kita perlu mencetak, kita akan mengubahnya menjadi karakter. Kali ini keluarannya akhirnya berupa huruf.
Copy kode kodenya sebagai berikut:
w
0
0
T
Jika kita ingin memproses karakter dari awal, bukan int, kita bisa langsung mengubah int menjadi karakter setelah memanggil karakter:
Copy kode kodenya sebagai berikut:
str.karakter()
.mapToObj(ch -> Character.valueOf((char)ch))
.forEach(Sistem.keluar::println);
Di sini kita menggunakan iterator internal dari Stream yang dikembalikan oleh chars(). Tentu saja, lebih dari metode ini dapat digunakan. Setelah mendapatkan objek Stream, kita bisa menggunakan metodenya, seperti map(), filter(), pengurangan(), dll. Kita dapat menggunakan metode filter() untuk memfilter karakter berupa angka:
Copy kode kodenya sebagai berikut:
str.karakter()
.filter(ch -> Karakter.isDigit(ch))
.forEach(ch -> printChar(ch));
Saat mengeluarkan keluaran dengan cara ini, kita hanya dapat melihat angka:
Copy kode kodenya sebagai berikut:
0
0
Demikian pula, selain meneruskan ekspresi lambda ke metode filter() dan forEach(), kita juga dapat menggunakan referensi metode.
Copy kode kodenya sebagai berikut:
str.karakter()
.filter(Karakter::isDigit)
.forEach(IterateString::printChar);
Referensi metode di sini menghilangkan perutean parameter yang berlebihan. Dalam contoh ini, kita juga melihat penggunaan yang berbeda dari dua metode sebelumnya. Pertama kali kami mereferensikan metode instan, yang kedua adalah metode referensi statis (System.out). Kali ini referensi ke metode statis - referensi metode telah membayar secara diam-diam.
Referensi ke metode instan dan metode statis semuanya terlihat sama: misalnya, String::toUpperCase dan Character::isDigit. Kompilator menentukan apakah metode tersebut merupakan metode instan atau metode statis untuk menentukan cara merutekan parameter. Jika ini adalah metode instan, ia akan menggunakan parameter masukan dari metode yang dihasilkan sebagai objek target pemanggilan metode, seperti parameter, toUpperCase(); (Tentu saja ada pengecualian, seperti objek target pemanggilan metode telah ditentukan, seperti System::out.println()). Selain itu, jika ini adalah metode statis, parameter masukan dari metode yang dihasilkan akan digunakan sebagai parameter metode yang direferensikan, seperti Character.isDigit(parameter). Lampiran 2 di halaman 152 berisi petunjuk rinci tentang cara menggunakan referensi metode dan sintaksisnya.
Meskipun referensi metode mudah digunakan, masih terdapat masalah - ambiguitas yang disebabkan oleh konflik penamaan metode. Jika metode pencocokan merupakan metode instan dan metode statis, kompilator akan melaporkan kesalahan karena ambiguitas metode. Misalnya, jika kita menulis Double::toString seperti ini, sebenarnya kita ingin mengubah tipe double menjadi string, tetapi compiler tidak tahu apakah harus memanggil metode instance dari public String toString() atau memanggil public static String toString.(double), karena kedua metode tersebut berkelas Double. Jika Anda menghadapi situasi seperti ini, jangan berkecil hati, cukup gunakan ekspresi lambda untuk menyelesaikannya.
Setelah kita merasa nyaman dengan pemrograman fungsional, kita dapat beralih antara ekspresi lambda dan referensi metode sesuka hati.
Di bagian ini kami menggunakan metode baru di Java 8 untuk melakukan iterasi pada string. Mari kita lihat peningkatan pada antarmuka Comparator.