Misalkan saya memiliki antarmuka umum:
interface MyComparable<T extends Comparable<T>> {
public int compare(T obj1, T obj2);
}
Dan metode sort
:
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable<T> comp) {
// sort the list
}
Saya bisa memanggil metode ini dan meneruskan ekspresi lambda sebagai argumen:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
Itu akan bekerja dengan baik.
Tetapi sekarang jika saya membuat antarmuka non-generik, dan metode generik:
interface MyComparable {
public <T extends Comparable<T>> int compare(T obj1, T obj2);
}
public static <T extends Comparable<T>>
void sort(List<T> list, MyComparable comp) {
}
Dan kemudian panggil ini seperti:
List<String> list = Arrays.asList("a", "b", "c");
sort(list, (a, b) -> a.compareTo(b));
Itu tidak dapat dikompilasi. Ini menunjukkan kesalahan pada ekspresi lambda yang mengatakan:
"Metode target bersifat umum"
Oke, ketika saya kompilasi menggunakan javac
, itu menunjukkan kesalahan berikut:
SO.java:20: error: incompatible types: cannot infer type-variable(s) T#1
sort(list, (a, b) -> a.compareTo(b));
^
(argument mismatch; invalid functional descriptor for lambda expression
method <T#2>(T#2,T#2)int in interface MyComparable is generic)
where T#1,T#2 are type-variables:
T#1 extends Comparable<T#1> declared in method <T#1>sort(List<T#1>,MyComparable)
T#2 extends Comparable<T#2> declared in method <T#2>compare(T#2,T#2)
1 error
Dari pesan error ini, sepertinya compiler tidak dapat menyimpulkan argumen type. Apakah itu masalahnya? Jika ya, mengapa bisa terjadi seperti ini?
Saya mencoba berbagai cara, mencari melalui internet. Kemudian saya menemukan artikel JavaCodeGeeks ini , yang menunjukkan caranya, jadi saya mencoba:
sort(list, <T extends Comparable<T>>(a, b) -> a.compareTo(b));
yang lagi-lagi tidak berfungsi, bertentangan dengan klaim artikel itu bahwa itu berfungsi. Mungkin itu dulu berfungsi di beberapa build awal.
Jadi pertanyaan saya adalah: Apakah ada cara untuk membuat ekspresi lambda untuk metode umum? Saya dapat melakukan ini menggunakan referensi metode, dengan membuat metode:
public static <T extends Comparable<T>> int compare(T obj1, T obj2) {
return obj1.compareTo(obj2);
}
di beberapa kelas katakan SO
, dan berikan sebagai:
sort(list, SO::compare);
Menggunakan referensi metode, saya menemukan cara lain untuk meneruskan argumen:
sumber
Cukup tunjuk kompilator versi yang tepat dari Pembanding generik dengan
(Comparator<String>)
Jadi jawabannya adalah
sort(list, (Comparator<String>)(a, b) -> a.compareTo(b));
sumber
incompatible types: java.util.Comparator<java.lang.String> cannot be converted to MyComparable
danMyComparable
tidak generik (tanpa tipe) jadi(MyComparable<String>)
tidak akan berhasilCompartor
?Apakah maksudmu seperti ini?:
Jenis apa lambda ini? Anda tidak dapat mengungkapkannya di Java dan oleh karena itu tidak dapat membuat ekspresi ini dalam aplikasi fungsi dan ekspresi harus dapat disusun.
Agar kebutuhan ini berhasil, Anda memerlukan dukungan untuk Jenis Peringkat2 di Java.
Metode diperbolehkan untuk menjadi umum tetapi oleh karena itu Anda tidak dapat menggunakannya sebagai ekspresi. Namun, mereka dapat dikurangi menjadi ekspresi lambda dengan mengkhususkan semua tipe generik yang diperlukan sebelum Anda dapat meneruskannya:
ClassName::<TypeName>methodName
sumber
"Of what type is this lambda? You couldn't express that in Java..."
Jenisnya akan disimpulkan menggunakan konteks, sama seperti lambda lainnya. Jenis lambda tidak diekspresikan secara eksplisit di lambda itu sendiri.