Saya melihat java.util.function.BiFunction, jadi saya bisa melakukan ini:
BiFunction<Integer, Integer, Integer> f = (x, y) -> { return 0; };
Bagaimana jika itu tidak cukup baik dan saya membutuhkan TriFungsi? Itu tidak ada!
TriFunction<Integer, Integer, Integer, Integer> f = (x, y, z) -> { return 0; };
Saya kira saya harus menambahkan bahwa saya tahu saya dapat mendefinisikan TriFungsi saya sendiri, saya hanya mencoba memahami alasan di balik tidak memasukkannya ke dalam pustaka standar.
Jawaban:
Sejauh yang saya tahu, hanya ada dua macam fungsi, destruktif dan konstruktif.
Sementara fungsi konstruktif, seperti namanya, mengkonstruksi sesuatu, fungsi destruktif menghancurkan sesuatu, tetapi tidak dengan cara yang mungkin Anda pikirkan sekarang.
Misalnya fungsinya
adalah salah satu yang konstruktif . Seperti yang Anda butuhkan untuk membangun sesuatu. Dalam contoh Anda membuat tupel (x, y) . Fungsi konstruktif memiliki masalah, karena tidak mampu menangani argumen yang tak terbatas. Tetapi yang terburuk adalah, Anda tidak bisa membiarkan argumen tetap terbuka. Anda tidak bisa hanya mengatakan "baiklah, biarkan x: = 1" dan coba setiap y yang mungkin ingin Anda coba. Anda harus membangun setiap kali seluruh tupel dengan
x := 1
. Jadi jika Anda ingin melihat apa fungsi kembali untuky := 1, y := 2, y := 3
Anda harus menulisf(1,1) , f(1,2) , f(1,3)
.Di Java 8, fungsi konstruktif harus ditangani (sebagian besar waktu) dengan menggunakan referensi metode karena tidak banyak keuntungan menggunakan fungsi lambda konstruktif. Mereka agak seperti metode statis. Anda dapat menggunakannya, tetapi tidak memiliki status nyata.
Jenis lainnya adalah yang merusak, ia mengambil sesuatu dan membongkar sejauh yang dibutuhkan. Misalnya fungsi destruktif
melakukan hal yang sama dengan fungsi
f
yang konstruktif. Manfaat dari fungsi destruktif adalah, Anda sekarang dapat menangani argumen tak terbatas, yang sangat nyaman untuk aliran, dan Anda dapat membiarkan argumen tetap terbuka. Jadi jika Anda ingin melihat lagi seperti apa hasilnya jikax := 1
dany := 1 , y := 2 , y := 3
, Anda dapat mengatakanh = g(1)
danh(1)
merupakan hasil untuky := 1
,h(2)
untuky := 2
danh(3)
untuky := 3
.Jadi di sini Anda memiliki keadaan tetap! Itu cukup dinamis dan seringkali itulah yang kami inginkan dari lambda.
Pola seperti Pabrik jauh lebih mudah jika Anda bisa menggunakan fungsi yang bekerja untuk Anda.
Yang merusak mudah digabungkan satu sama lain. Jika jenisnya benar, Anda dapat membuatnya sesuka Anda. Dengan menggunakan itu, Anda dapat dengan mudah menentukan morfisme yang membuat pengujian (dengan nilai yang tidak dapat diubah) jauh lebih mudah!
Anda juga dapat melakukannya dengan yang konstruktif, tetapi komposisi yang merusak terlihat lebih bagus dan lebih seperti daftar atau dekorator, dan yang konstruktif terlihat sangat mirip dengan pohon. Dan hal-hal seperti mundur dengan fungsi konstruktif tidak baik. Anda dapat menyimpan sebagian fungsi dari fungsi destruktif (pemrograman dinamis), dan pada "backtrack" gunakan saja fungsi destruktif lama. Itu membuat kode jauh lebih kecil dan lebih mudah dibaca. Dengan fungsi konstruktif Anda memiliki lebih banyak atau lebih sedikit untuk mengingat semua argumen, yang bisa jadi banyak.
Jadi mengapa ada kebutuhan
BiFunction
harus lebih banyak pertanyaan daripada mengapa tidak adaTriFunction
?Pertama-tama, sering kali Anda hanya memiliki sedikit nilai (kurang dari 3) dan hanya memerlukan hasil, jadi fungsi destruktif yang normal tidak akan diperlukan sama sekali, fungsi konstruktif sudah cukup. Dan ada hal-hal seperti monad yang sangat membutuhkan fungsi konstruktif. Tapi selain itu, sebenarnya tidak ada banyak alasan bagus mengapa ada
BiFunction
. Yang tidak berarti itu harus dihapus! Saya berjuang untuk Monads saya sampai saya mati!Jadi, jika Anda memiliki banyak argumen, yang tidak dapat Anda gabungkan ke dalam kelas container yang logis, dan jika Anda membutuhkan fungsi yang konstruktif, gunakan referensi metode. Jika tidak, cobalah menggunakan kemampuan baru yang diperoleh dari fungsi destruktif, Anda mungkin menemukan diri Anda melakukan banyak hal dengan baris kode yang jauh lebih sedikit.
sumber
BiFunction
dibuat untuk memudahkan reduksi data, dan kebanyakanStream
operasi terminal hanyalah reduksi data. Contoh yang baik adalahBinaryOperator<T>
, digunakan di banyak orangCollectors
. Elemen pertama dikurangi dengan elemen kedua, kemudian dapat dikurangi dengan elemen berikutnya, dan seterusnya. Tentu saja, Anda dapat membuat sebuahFunction<T, Function<T, T>
func = x -> (y -> / * kode reduksi di sini * /). Tapi, serius? Semua ini dapat Anda lakukan dengan mudahBinaryOperator<T> func = (x, y) -> /*reduction code here*/
. Plus, pendekatan pengurangan data ini tampaknya sangat mirip dengan pendekatan "destruktif" Anda bagi saya.Function<Integer,Integer> f = (x,y) -> x + y
Java yang valid, padahal sebenarnya tidak. Itu seharusnya menjadi BiFungsi untuk memulai!Jika Anda membutuhkan TriFungsi, lakukan ini:
Mengikuti program kecil menunjukkan bagaimana itu dapat digunakan. Ingatlah bahwa tipe hasil ditentukan sebagai parameter tipe generik terakhir.
Saya kira jika ada penggunaan praktis untuk TriFunction di
java.util.*
ataujava.lang.*
itu akan ditentukan. Saya tidak akan pernah melampaui 22 argumen ;-) Yang saya maksud dengan itu, semua kode baru yang memungkinkan untuk mengalirkan koleksi tidak pernah memerlukan TriFungsi sebagai salah satu parameter metode. Jadi tidak disertakan.MEMPERBARUI
Untuk kelengkapan dan mengikuti penjelasan fungsi destruktif di jawaban lain (terkait kari), berikut cara TriFungsi bisa ditiru tanpa antarmuka tambahan:
Tentu saja, dimungkinkan untuk menggabungkan fungsi dengan cara lain, misalnya:
Meskipun kari akan menjadi hal alami untuk bahasa apa pun yang mendukung pemrograman fungsional di luar lambda, Java tidak dibangun dengan cara ini dan, meskipun dapat dicapai, kodenya sulit dipelihara, dan terkadang dibaca. Namun, ini sangat membantu sebagai latihan, dan terkadang fungsi parsial memiliki tempat yang tepat dalam kode Anda.
sumber
TriFunction<Integer,Integer,Integer,Integer> comp = (x,y,z) -> x + y + z; comp = comp.andThen(s -> s * 2); int result = comp.apply(1, 2, 3); //12
Lihat stackoverflow.com/questions/19834611/…andThen()
contoh penggunaan ke jawabannya.BiFunction
digunakan diStream
API untuk melakukan pengurangan data, yang sangat mirip dengan pendekatan kari bagi saya: Anda tidak pernah mengambil lebih dari dua argumen, dan Anda dapat memproses sejumlah elemen, satu pengurangan pada satu waktu (lihat komentar saya tentang jawaban yang diterima, saya akan senang mengetahui jika saya salah melihatnya seperti itu).Alternatifnya adalah, tambahkan dependensi di bawah ini,
Sekarang, Anda dapat menggunakan Fungsi Vavr, seperti di bawah ini hingga 8 argumen,
3 argumen:
5 argumen:
sumber
vavr
perpustakaan - itu membuat pemrograman gaya fungsional dapat ditanggung di Java sebanyak mungkin.Saya Memiliki pertanyaan yang hampir sama dan jawaban parsial. Tidak yakin apakah jawaban konstruktif / dekonstruktif adalah yang ada dalam pikiran desainer bahasa. Saya pikir memiliki 3 dan lebih upto N memiliki kasus penggunaan yang valid.
Saya berasal dari .NET. dan di .NET Anda memiliki Func dan Action untuk fungsi void. Predikat dan beberapa kasus khusus lainnya juga ada. Lihat: https://msdn.microsoft.com/en-us/library/bb534960(v=vs.110).aspx
Saya bertanya-tanya apa alasan mengapa desainer bahasa memilih Function, Bifunction dan tidak melanjutkan hingga DecaExiFunction?
Jawaban untuk bagian kedua adalah penghapusan tipe. Setelah kompilasi tidak ada perbedaan antara Func dan Func. Oleh karena itu, berikut ini tidak dapat dikompilasi:
Fungsi dalam digunakan untuk menghindari masalah kecil lainnya. Eclipse bersikeras memiliki kedua kelas dalam file bernama Fungsi di direktori yang sama ... Tidak yakin apakah ini masalah kompilator saat ini. Tapi saya tidak bisa mengubah kesalahan di Eclipse.
Func digunakan untuk mencegah bentrokan nama dengan tipe Fungsi java.
Jadi jika Anda ingin menambahkan Func dari 3 hingga 16 argumen Anda dapat melakukan dua hal.
Contoh cara kedua:
dan
Apa pendekatan terbaik?
Dalam contoh di atas saya tidak menyertakan implementasi untuk metode andThen () dan compose (). Jika Anda menambahkan ini, Anda harus menambahkan masing-masing 16 kelebihan beban: TriFunc harus memiliki andthen () dengan 16 argumen. Itu akan memberi Anda kesalahan kompilasi karena dependensi melingkar. Anda juga tidak akan mengalami kelebihan beban ini untuk Fungsi dan BiFungsi. Oleh karena itu, Anda juga harus mendefinisikan Func dengan satu argumen dan Func dengan dua argumen. Dalam dependensi melingkar NET akan dielakkan dengan menggunakan metode ekstensi yang tidak ada di Jawa.
sumber
andThen
16 argumen? Hasil dari fungsi di Java adalah nilai tunggal.andThen
mengambil nilai ini dan melakukan sesuatu dengannya. Juga, tidak ada masalah dengan penamaan. Nama kelas harus berbeda dan berada dalam file berbeda dengan nama yang sama - mengikuti logika yang ditetapkan oleh pengembang bahasa Java dengan Fungsi dan BiFungsi. Selain itu, semua nama berbeda ini diperlukan jika tipe argumen berbeda. Seseorang dapat membuatVargFunction(T, R) { R apply(T.. t) ... }
untuk satu tipe.Saya menemukan kode sumber untuk BiFunction di sini:
https://github.com/JetBrains/jdk8u_jdk/blob/master/src/share/classes/java/util/function/BiFunction.java
Saya memodifikasinya untuk membuat TriFungsi. Seperti BiFunction, ia menggunakan andThen () dan bukan compose (), jadi untuk beberapa aplikasi yang membutuhkan compose (), ini mungkin tidak sesuai. Seharusnya tidak masalah untuk jenis objek normal. Artikel bagus tentang andThen () dan compose () dapat ditemukan di sini:
http://www.deadcoderising.com/2015-09-07-java-8-functional-composition-using-compose-and-andthen/
sumber
Anda juga dapat membuat fungsi Anda sendiri dengan menggunakan 3 parameter
sumber
Anda tidak selalu bisa berhenti di TriFunction. Terkadang, Anda mungkin perlu memberikan sejumlah n parameter ke fungsi Anda. Kemudian tim dukungan harus membuat QuadFungsi untuk memperbaiki kode Anda. Solusi jangka panjang adalah membuat Objek dengan parameter ekstra dan kemudian menggunakan Fungsi atau BiFungsi yang sudah jadi.
sumber