Saya punya metode yang sekitar sepuluh baris kode. Saya ingin membuat lebih banyak metode yang melakukan hal yang persis sama, kecuali untuk perhitungan kecil yang akan mengubah satu baris kode. Ini adalah aplikasi yang sempurna untuk melewatkan pointer fungsi untuk mengganti satu baris itu, tetapi Java tidak memiliki pointer fungsi. Apa alternatif terbaik saya?
java
closures
function-pointers
Bill the Lizard
sumber
sumber
::
operator, di sisi lain ...Jawaban:
Kelas dalam anonim
Katakanlah Anda ingin memiliki fungsi yang diteruskan dengan
String
param yang mengembalikan sebuahint
.Pertama, Anda harus mendefinisikan antarmuka dengan fungsi sebagai satu-satunya anggota, jika Anda tidak dapat menggunakan kembali yang sudah ada.
Metode yang mengambil pointer hanya akan menerima
StringFunction
contoh seperti:Dan akan disebut seperti ini:
EDIT: Di Java 8, Anda bisa menyebutnya dengan ekspresi lambda:
sumber
Untuk setiap "pointer fungsi", saya akan membuat kelas functor kecil yang mengimplementasikan perhitungan Anda. Tentukan antarmuka yang akan diimplementasikan oleh semua kelas, dan berikan instance objek-objek itu ke fungsi Anda yang lebih besar. Ini adalah kombinasi dari " pola perintah ", dan " pola strategi ".
@ sblundy contohnya bagus.
sumber
Ketika ada sejumlah perhitungan berbeda yang telah ditentukan yang dapat Anda lakukan dalam satu baris itu, menggunakan enum adalah cara yang cepat namun jelas untuk menerapkan pola strategi.
Jelas, deklarasi metode strategi, serta tepat satu contoh dari setiap implementasi semua didefinisikan dalam satu kelas / file.
sumber
Anda perlu membuat antarmuka yang menyediakan fungsi yang ingin Anda sampaikan. misalnya:
Kemudian, ketika Anda harus melewati suatu fungsi, Anda bisa mengimplementasikan antarmuka itu:
Akhirnya, fungsi peta menggunakan yang diteruskan di Function1 sebagai berikut:
Anda sering dapat menggunakan Runnable sebagai ganti antarmuka Anda sendiri jika Anda tidak perlu memasukkan parameter, atau Anda dapat menggunakan berbagai teknik lain untuk membuat jumlah param lebih sedikit "diperbaiki" tetapi biasanya merupakan pertukaran dengan keamanan jenis. (Atau Anda dapat menimpa konstruktor untuk objek fungsi Anda untuk lulus dalam params dengan cara itu .. ada banyak pendekatan, dan beberapa bekerja lebih baik dalam keadaan tertentu.)
sumber
Referensi metode menggunakan
::
operatorAnda dapat menggunakan referensi metode dalam argumen metode di mana metode menerima antarmuka fungsional . Antarmuka fungsional adalah semua antarmuka yang hanya berisi satu metode abstrak. (Antarmuka fungsional dapat berisi satu atau lebih metode standar atau metode statis.)
IntBinaryOperator
adalah antarmuka fungsional. Metode abstraknyaapplyAsInt
,, menerima duaint
s sebagai parameternya dan mengembalikan sebuahint
.Math.max
juga menerima duaint
dan mengembalikan sebuahint
. Dalam contoh ini,A.method(Math::max);
membuatparameter.applyAsInt
kirim dua nilai inputnyaMath.max
dan kembalikan hasilnyaMath.max
.Secara umum, Anda dapat menggunakan:
dari pada:
yang merupakan kependekan dari:
Untuk informasi lebih lanjut, lihat :: operator (titik dua) di Java 8 dan Spesifikasi Bahasa Java §15.13 .
sumber
Anda juga dapat melakukan ini (yang dalam beberapa kesempatan RARE masuk akal). Masalahnya (dan ini adalah masalah besar) adalah Anda kehilangan semua jenis keamanan menggunakan kelas / antarmuka dan Anda harus berurusan dengan kasus di mana metode ini tidak ada.
Itu memang memiliki "manfaat" bahwa Anda dapat mengabaikan pembatasan akses dan memanggil metode pribadi (tidak ditampilkan dalam contoh, tetapi Anda dapat memanggil metode yang biasanya tidak dikompilasi oleh kompiler).
Sekali lagi, ini adalah kasus langka yang masuk akal, tetapi pada kesempatan itu adalah alat yang bagus untuk dimiliki.
sumber
Jika Anda hanya memiliki satu baris yang berbeda, Anda dapat menambahkan parameter seperti flag dan pernyataan if (flag) yang memanggil satu baris atau yang lainnya.
sumber
Anda mungkin juga tertarik untuk mendengar tentang pekerjaan yang sedang berlangsung untuk Java 7 yang melibatkan penutupan:
Bagaimana kondisi penutupan saat ini di Jawa?
http://gafter.blogspot.com/2006/08/closures-for-java.html
http://tech.puredanger.com/java7/#closures
sumber
Java 8 Interface Fungsional dan Referensi Metode menggunakan
::
operator.Java 8 mampu mempertahankan referensi metode (MyClass :: baru) dengan " @Functional Interface pointer "@Functional ". Tidak perlu untuk nama metode yang sama, hanya tanda tangan metode yang sama diperlukan.
Contoh:
Jadi, apa yang kita miliki di sini?
ANDA HARUS MENGGUNAKAN FUNGSI FUNGSIONAL UNTUK MENDENGARKAN HANYA DAN HANYA UNTUK ITU!
Karena semua fungsi pointer seperti itu benar-benar buruk untuk keterbacaan kode dan kemampuan untuk memahami. Namun, referensi metode langsung terkadang berguna, dengan foreach misalnya.
Ada beberapa Antarmuka Fungsional yang telah ditentukan:
Untuk versi Java yang lebih lama Anda harus mencoba Guava Libraries, yang memiliki fungsi dan sintaksis yang sama, seperti yang telah disebutkan oleh Adrian Petrescu di atas.
Untuk penelitian tambahan, lihat Java 8 Cheatsheet
dan terima kasih kepada The Guy with The Hat untuk Spesifikasi Bahasa Jawa §15.13 tautan.
sumber
@ sblundy adalah jawaban yang bagus, tetapi kelas-kelas dalam anonim memiliki dua kelemahan kecil, yang utama adalah bahwa mereka cenderung tidak dapat digunakan kembali dan yang kedua adalah sintaksis yang besar.
Yang menyenangkan adalah polanya berkembang menjadi kelas penuh tanpa perubahan di kelas utama (yang melakukan perhitungan).
Saat Anda membuat instance kelas baru Anda bisa mengirimkan parameter ke kelas itu yang dapat bertindak sebagai konstanta dalam persamaan Anda - jadi jika salah satu kelas dalam Anda terlihat seperti ini:
tetapi terkadang Anda membutuhkannya yaitu:
dan mungkin yang ketiga yaitu:
Daripada membuat dua kelas dalam anonim atau menambahkan parameter "passthrough", Anda bisa membuat kelas ACTUAL tunggal yang Anda instantiate sebagai:
Itu hanya akan menyimpan konstanta di kelas dan menggunakannya dalam metode yang ditentukan dalam antarmuka.
Bahkan, jika TAHU bahwa fungsi Anda tidak akan disimpan / digunakan kembali, Anda bisa melakukan ini:
Tapi kelas yang tidak bisa diubah lebih aman - saya tidak bisa memberikan pembenaran untuk membuat kelas seperti ini bisa berubah.
Saya benar-benar hanya memposting ini karena saya merasa ngeri setiap kali saya mendengar kelas batin anonim - Saya telah melihat banyak kode berlebihan yang "Diperlukan" karena hal pertama yang dilakukan programmer adalah pergi anonim ketika ia seharusnya menggunakan kelas aktual dan tidak pernah memikirkan kembali keputusannya.
sumber
Pustaka Google Guava , yang menjadi sangat populer, memiliki fungsi dan predikat objek generik yang telah mereka kerjakan ke banyak bagian API mereka.
sumber
Kedengarannya seperti pola strategi bagi saya. Lihat pola Java fluffycat.com.
sumber
Salah satu hal yang saya sangat rindukan ketika pemrograman di Jawa adalah fungsi callback. Satu situasi di mana kebutuhan untuk ini terus muncul dengan sendirinya adalah dalam memproses hierarki secara rekursif di mana Anda ingin melakukan beberapa tindakan spesifik untuk setiap item. Seperti berjalan di pohon direktori, atau memproses struktur data. Minimalis di dalam diriku benci harus mendefinisikan antarmuka dan kemudian implementasi untuk setiap kasus tertentu.
Suatu hari saya mendapati diri saya bertanya-tanya mengapa tidak? Kami memiliki pointer metode - objek Metode. Dengan mengoptimalkan kompiler JIT, doa reflektif benar-benar tidak membawa penalti kinerja yang besar lagi. Dan selain di samping, katakanlah, menyalin file dari satu lokasi ke lokasi lain, biaya pemanggilan metode yang direfleksikan menjadi tidak berarti.
Ketika saya memikirkannya lebih lanjut, saya menyadari bahwa panggilan balik dalam paradigma OOP membutuhkan pengikatan suatu objek dan metode secara bersamaan - masukkan objek Callback.
Lihat solusi berbasis refleksi saya untuk Callback di Jawa . Gratis untuk penggunaan apa pun.
sumber
ya, utas ini sudah cukup tua, jadi sangat mungkin jawaban saya tidak membantu untuk pertanyaan itu. Tetapi karena utas ini membantu saya menemukan solusi saya, saya akan tetap melakukannya di sini.
Saya perlu menggunakan metode statis variabel dengan input yang dikenal dan output yang dikenal (keduanya ganda ). Jadi, mengetahui paket metode dan nama, saya bisa bekerja sebagai berikut:
untuk fungsi yang menerima satu rangkap sebagai parameter.
Jadi, dalam situasi konkret saya, saya memulainya dengan
dan menggunakannya kemudian dalam situasi yang lebih kompleks dengan
di mana aktivitas adalah nilai ganda yang berubah-ubah. Saya berpikir mungkin melakukan ini sedikit lebih abstrak dan menggeneralisasikannya, seperti yang dilakukan SoftwareMonkey, tetapi saat ini saya cukup senang dengan cara itu. Tiga baris kode, tidak perlu kelas dan antarmuka, itu tidak terlalu buruk.
sumber
code
penurunan harga, aku terlalu tidak sabar dan bodoh untuk menemukannya ;-)Untuk melakukan hal yang sama tanpa antarmuka untuk berbagai fungsi:
sumber
Lihat lambdaj
http://code.google.com/p/lambdaj/
dan khususnya fitur penutupan barunya
http://code.google.com/p/lambdaj/wiki/Closures
dan Anda akan menemukan cara yang sangat mudah dibaca untuk mendefinisikan closure atau fungsi pointer tanpa membuat antarmuka yang tidak berarti atau menggunakan kelas-kelas dalam yang jelek
sumber
Wow, mengapa tidak hanya membuat kelas Delegasi yang tidak terlalu sulit mengingat bahwa saya sudah melakukannya untuk java dan menggunakannya untuk mengirimkan parameter di mana T adalah tipe pengembalian. Saya minta maaf tetapi sebagai programmer C ++ / C # secara umum baru belajar java, saya perlu pointer fungsi karena mereka sangat berguna. Jika Anda terbiasa dengan kelas apa pun yang berkaitan dengan Informasi Metode, Anda dapat melakukannya. Di perpustakaan java itu adalah java.lang.reflect.method.
Jika Anda selalu menggunakan antarmuka, Anda harus selalu mengimplementasikannya. Dalam penanganan acara, sebenarnya tidak ada cara yang lebih baik untuk mendaftar / membatalkan pendaftaran dari daftar penangan, tetapi untuk delegasi di mana Anda harus menyampaikan fungsi dan bukan tipe nilai, membuat kelas delegasi untuk menanganinya untuk outclass antarmuka.
sumber
Tidak ada jawaban Java 8 yang memberikan contoh lengkap, kohesif, jadi ini dia.
Deklarasikan metode yang menerima "function pointer" sebagai berikut:
Sebut dengan menyediakan fungsi dengan ekspresi lambda:
sumber
Jika ada yang berjuang untuk melewati fungsi yang mengambil satu set parameter untuk menentukan perilakunya, tetapi set parameter lain untuk dieksekusi, seperti skema:
lihat Fungsi Pass dengan Perilaku yang Ditentukan Parameter di Jawa
sumber
Sejak Java8, Anda dapat menggunakan lambdas, yang juga memiliki perpustakaan di API SE 8 resmi.
Penggunaan: Anda perlu menggunakan antarmuka dengan hanya satu metode abstrak. Buat instance darinya (Anda mungkin ingin menggunakan java SE 8 yang sudah disediakan) seperti ini:
Untuk informasi lebih lanjut, periksa dokumentasi: https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
sumber
Sebelum Java 8, pengganti terdekat untuk fungsi-fungsi seperti pointer adalah kelas anonim. Sebagai contoh:
Tetapi sekarang di Java 8 kami memiliki alternatif yang sangat rapi yang dikenal sebagai ekspresi lambda , yang dapat digunakan sebagai:
di mana isBiggerThan adalah metode di
CustomClass
. Kami juga dapat menggunakan referensi metode di sini:sumber