Saya bermain-main dengan Java 8 untuk mencari tahu bagaimana fungsinya sebagai warga negara kelas satu. Saya memiliki cuplikan berikut:
package test;
import java.util.*;
import java.util.function.*;
public class Test {
public static void myForEach(List<Integer> list, Function<Integer, Void> myFunction) {
list.forEach(functionToBlock(myFunction));
}
public static void displayInt(Integer i) {
System.out.println(i);
}
public static void main(String[] args) {
List<Integer> theList = new ArrayList<>();
theList.add(1);
theList.add(2);
theList.add(3);
theList.add(4);
theList.add(5);
theList.add(6);
myForEach(theList, Test::displayInt);
}
}
Apa yang saya coba lakukan adalah meneruskan metode displayInt
ke metode myForEach
menggunakan referensi metode. Untuk mengkompilasi menghasilkan kesalahan berikut:
src/test/Test.java:9: error: cannot find symbol
list.forEach(functionToBlock(myFunction));
^
symbol: method functionToBlock(Function<Integer,Void>)
location: class Test
src/test/Test.java:25: error: method myForEach in class Test cannot be applied to given ty
pes;
myForEach(theList, Test::displayInt);
^
required: List<Integer>,Function<Integer,Void>
found: List<Integer>,Test::displayInt
reason: argument mismatch; bad return type in method reference
void cannot be converted to Void
Kompiler mengeluh itu void cannot be converted to Void
. Saya tidak tahu bagaimana cara menentukan jenis antarmuka fungsi di tanda tangan myForEach
sedemikian rupa sehingga kode dikompilasi. Saya tahu saya bisa dengan mudah mengubah jenis kembali displayInt
ke Void
dan kemudian kembali null
. Namun, mungkin ada situasi di mana tidak mungkin untuk mengubah metode yang ingin saya sampaikan di tempat lain. Apakah ada cara mudah untuk menggunakannya kembali displayInt
?
Block
diubah untukConsumer
rilis terbaru JDK 8 APIMethodHandle
), dan menggunakan ini, kompiler Java mampu menghasilkan kode yang lebih efisien, misalnya menerapkan lambdas tanpa penutup sebagai metode statis, sehingga mencegah pembentukan kelas tambahan.Function<Void, Void>
adalahRunnable
.Runnable
danCallable
antarmuka tertulis bahwa mereka seharusnya digunakan bersama dengan utas . Konsekuensi yang mengganggu dari itu adalah bahwa beberapa alat analisis statis (seperti Sonar) akan mengeluh jika Anda memanggilrun()
metode secara langsung.Ketika Anda perlu menerima fungsi sebagai argumen yang tidak menggunakan argumen dan tidak mengembalikan hasil (batal), menurut pendapat saya masih lebih baik untuk memiliki sesuatu seperti
di suatu tempat dalam kode Anda. Dalam kursus pemrograman fungsional saya, kata 'thunk' digunakan untuk menggambarkan fungsi-fungsi tersebut. Mengapa itu tidak ada di java.util.fungsi adalah di luar pemahaman saya.
Dalam kasus lain saya menemukan bahwa bahkan ketika java.util.function memang memiliki sesuatu yang cocok dengan tanda tangan yang saya inginkan - itu masih tidak selalu terasa benar ketika penamaan antarmuka tidak cocok dengan penggunaan fungsi dalam kode saya. Saya kira itu adalah poin yang sama yang dibuat di tempat lain di sini mengenai 'Runnable' - yang merupakan istilah yang terkait dengan kelas Thread - jadi meskipun mungkin dia harus membubuhkan tanda tangan yang saya butuhkan, masih mungkin membingungkan pembaca.
sumber
Runnable
tidak mengizinkan pengecualian yang diperiksa, menjadikannya tidak berguna untuk banyak aplikasi. KarenaCallable<Void>
tidak berguna juga, Anda perlu mendefinisikan sendiri tampaknya. Jelek.Setel jenis kembali ke
Void
alih-alihvoid
danreturn null
ATAU
sumber
Saya rasa Anda harus menggunakan antarmuka Konsumen alih-alih
Function<T, R>
.Konsumen pada dasarnya adalah antarmuka fungsional yang dirancang untuk menerima nilai dan tidak mengembalikan apa pun (mis. Batal)
Dalam kasus Anda, Anda dapat membuat konsumen di tempat lain dalam kode Anda seperti ini:
Kemudian Anda dapat mengganti
myForEach
kode Anda dengan cuplikan di bawah ini:Anda memperlakukan fungsi saya sebagai objek kelas satu.
sumber