Catatan: pertanyaan ini berasal dari tautan mati yang merupakan pertanyaan SO sebelumnya, tetapi begini ...
Lihat kode ini ( catatan: Saya tahu bahwa kode ini tidak akan "berfungsi" dan yang Integer::compare
harus digunakan - Saya baru saja mengekstraknya dari pertanyaan yang ditautkan ):
final ArrayList <Integer> list
= IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());
System.out.println(list.stream().max(Integer::max).get());
System.out.println(list.stream().min(Integer::min).get());
Menurut javadoc dari .min()
dan .max()
, argumen keduanya harus a Comparator
. Namun di sini referensi metode adalah metode statis Integer
kelas.
Jadi, mengapa ini dikompilasi?
java
java-8
java-stream
Fge
sumber
sumber
Integer::compare
bukanInteger::max
danInteger::min
.Integer
bukan metodeComparator
.Jawaban:
Izinkan saya menjelaskan apa yang terjadi di sini, karena tidak jelas!
Pertama,
Stream.max()
terima contohComparator
agar item dalam aliran dapat dibandingkan satu sama lain untuk menemukan minimum atau maksimum, dalam urutan optimal yang tidak perlu Anda khawatirkan terlalu banyak.Jadi pertanyaannya, tentu saja, mengapa
Integer::max
diterima? Bagaimanapun, ini bukan pembanding!Jawabannya adalah bagaimana fungsi lambda baru berfungsi di Java 8. Ini bergantung pada konsep yang secara informal dikenal sebagai antarmuka "metode abstrak tunggal", atau antarmuka "SAM". Idenya adalah bahwa setiap antarmuka dengan satu metode abstrak dapat secara otomatis diimplementasikan oleh lambda - atau referensi metode - yang tanda tangannya metode cocok untuk satu metode pada antarmuka. Jadi memeriksa
Comparator
antarmuka (versi sederhana):Jika suatu metode mencari
Comparator<Integer>
, maka pada dasarnya mencari tanda tangan ini:Saya menggunakan "xxx" karena nama metode tidak digunakan untuk tujuan pencocokan .
Oleh karena itu, keduanya
Integer.min(int a, int b)
danInteger.max(int a, int b)
cukup dekat sehingga autoboxing akan memungkinkan ini muncul sebagaiComparator<Integer>
dalam konteks metode.sumber
list.stream().mapToInt(i -> i).max().get()
..getAsInt()
alih-alihget()
, karena Anda berurusan denganOptionalInt
.max()
fungsi!Comparator
dokumentasi kita dapat melihat bahwa itu dihiasi dengan anotasi@FunctionalInterface
. Dekorator ini adalah keajaiban yang memungkinkanInteger::max
danInteger::min
diubah menjadiComparator
.@FunctionalInterface
terutama untuk tujuan dokumentasi saja, karena kompiler dapat dengan senang hati melakukan ini dengan antarmuka apa pun dengan satu metode abstrak tunggal.Comparator
adalah antarmuka fungsional , danInteger::max
sesuai dengan antarmuka itu (setelah autoboxing / unboxing dipertimbangkan). Dibutuhkan duaint
nilai dan mengembalikanint
- seperti yang Anda harapkanComparator<Integer>
untuk (sekali lagi, menyipitkan mata untuk mengabaikan perbedaan Integer / int).Namun, saya tidak akan mengharapkan untuk melakukan hal yang benar, mengingat bahwa
Integer.max
tidak sesuai dengan semantik dariComparator.compare
. Dan memang itu tidak benar-benar bekerja secara umum. Misalnya, buat satu perubahan kecil:... dan sekarang
max
nilainya -20 danmin
nilainya -1.Sebaliknya, kedua panggilan harus menggunakan
Integer::compare
:sumber
Comparator<Integer>
pastiint compare(Integer, Integer)
... itu tidak membingungkan bahwa Jawa memungkinkan referensi metodeint max(int, int)
untuk mengkonversi ke ...Integer::max
? Dari sudut pandangnya Anda melewati fungsi yang memenuhi spesifikasinya, itu saja yang benar-benar bisa berjalan.Comparator.compare
. Itu harus mengembalikanenum
dari{LessThan, GreaterThan, Equal}
, bukanint
. Dengan begitu, antarmuka fungsional tidak akan benar-benar cocok dan Anda akan mendapatkan kesalahan kompilasi. TKI: tipe tanda tangan dariComparator.compare
tidak cukup menangkap semantik dari apa artinya membandingkan dua objek, dan dengan demikian antarmuka lain yang sama sekali tidak ada hubungannya dengan membandingkan objek secara tidak sengaja memiliki tipe tanda tangan yang sama.Ini berfungsi karena
Integer::min
memutuskan untuk mengimplementasikanComparator<Integer>
antarmuka.Referensi metode
Integer::min
resolves toInteger.min(int a, int b)
, resolved toIntBinaryOperator
, dan mungkin autoboxing terjadi di suatu tempat membuatnya menjadiBinaryOperator<Integer>
.Dan metode
min()
respmax()
dari antarmukaStream<Integer>
memintaComparator<Integer>
untuk diimplementasikan.Sekarang ini teratasi dengan metode tunggal
Integer compareTo(Integer o1, Integer o2)
. Yang merupakan tipeBinaryOperator<Integer>
.Dan dengan demikian keajaiban telah terjadi karena kedua metode adalah a
BinaryOperator<Integer>
.sumber
Integer::min
alat ituComparable
. Ini bukan tipe yang bisa mengimplementasikan apa pun. Tetapi dievaluasi menjadi objek yang mengimplementasikanComparable
.Comparator<Integer>
adalah antarmuka metode tunggal abstrak (alias "fungsional"), danInteger::min
memenuhi kontraknya, sehingga lambda dapat diartikan sebagai ini. Saya tidak tahu bagaimana Anda melihat BinaryOperator berperan di sini (atau IntBinaryOperator, baik) - tidak ada hubungan subtyping antara itu dan Pembanding.Terlepas dari informasi yang diberikan oleh David M. Lloyd orang dapat menambahkan bahwa mekanisme yang memungkinkan ini disebut pengetikan target .
Idenya adalah bahwa jenis kompiler menetapkan untuk ekspresi lambda atau referensi metode tidak hanya bergantung pada ekspresi itu sendiri, tetapi juga pada di mana ia digunakan.
Target ekspresi adalah variabel yang hasilnya ditetapkan atau parameter yang hasilnya diteruskan.
Ekspresi Lambda dan referensi metode diberikan jenis yang cocok dengan jenis target mereka, jika jenis tersebut dapat ditemukan.
Lihat bagian Ketikkan Inferensi di Tutorial Java untuk informasi lebih lanjut.
sumber
Saya mengalami kesalahan dengan array mendapatkan maks dan min jadi solusi saya adalah:
sumber