Saya bermain dengan lambdas di Java 8 dan saya mendapat peringatan local variables referenced from a lambda expression must be final or effectively final
. Saya tahu bahwa ketika saya menggunakan variabel di dalam kelas anonim mereka harus final di kelas luar, tapi tetap saja - apa perbedaan antara final dan final efektif ?
351
Jawaban:
Misalnya, anggap bahwa variabel
numberLength
tidak dinyatakan final, dan Anda menambahkan pernyataan penugasan yang ditandai diPhoneNumber
konstruktor:Karena pernyataan penugasan ini, variabel numberLength tidak lagi final secara efektif. Akibatnya, kompiler Java menghasilkan pesan kesalahan yang mirip dengan "variabel lokal yang dirujuk dari kelas dalam harus final atau efektif final" di mana kelas dalam PhoneNumber mencoba mengakses variabel numberLength:
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
sumber
numberLength
menjadi variabel lokal dari metode ini.Saya menemukan cara paling sederhana untuk menjelaskan "efektif akhir" adalah membayangkan menambahkan
final
pengubah ke deklarasi variabel. Jika, dengan perubahan ini, program terus berperilaku dengan cara yang sama, baik pada waktu kompilasi maupun pada saat run time, maka variabel tersebut secara efektif final.sumber
case k
memerlukan ekspresi konstan yang bisa menjadi variabel konstan ("Variabel konstan adalah variabel akhir dari tipe primitif atau tipe String yang diinisialisasi dengan ekspresi konstan" JLS 4.12.4 ) yang merupakan kasus khusus dari final variabel.Menurut dokumen :
Pada dasarnya, jika kompiler menemukan suatu variabel tidak muncul dalam tugas di luar inisialisasi, maka variabel tersebut dianggap efektif akhir .
Sebagai contoh, pertimbangkan beberapa kelas:
sumber
bar
dalam contoh Anda bukan variabel lokal, tetapi bidang. "Secara efektif final" dalam pesan kesalahan seperti di atas tidak berlaku untuk semua bidang.bar
adalah parameter di sini, bukan bidang.'Final efektif' adalah variabel yang tidak akan memberikan kesalahan kompilator jika itu akan ditambahkan oleh 'final'
Dari sebuah artikel oleh 'Brian Goetz',
lambda-state-final- Brian Goetz
sumber
Variabel di bawah ini final , jadi kami tidak dapat mengubah nilainya setelah diinisialisasi. Jika kami mencoba, kami akan mendapatkan kesalahan kompilasi ...
Tetapi jika kita membuat variabel seperti ini, kita dapat mengubah nilainya ...
Namun di Java 8 , semua variabel bersifat final secara default. Tetapi keberadaan baris ke-2 dalam kode membuatnya tidak final . Jadi jika kita menghapus baris ke-2 dari kode di atas, variabel kita sekarang "efektif akhir" ...
Jadi .. Setiap variabel yang ditugaskan satu kali dan hanya sekali, adalah "efektif akhir" .
sumber
Variabel adalah final atau efektif final ketika diinisialisasi sekali dan tidak pernah bermutasi di kelas pemiliknya. Dan kita tidak dapat menginisialisasi dalam loop atau kelas dalam .
Final :
Final Efektif :
sumber
Ketika ekspresi lambda menggunakan variabel lokal yang ditugaskan dari ruang terlampirnya ada batasan penting. Ekspresi lambda hanya dapat menggunakan variabel lokal yang nilainya tidak berubah. Pembatasan itu disebut sebagai " penangkapan variabel " yang digambarkan sebagai; nilai penangkapan ekspresi lambda, bukan variabel .
Variabel lokal yang menggunakan ekspresi lambda dikenal sebagai " efektif akhir ".
Variabel akhir yang efektif adalah variabel yang nilainya tidak berubah setelah ditetapkan pertama kali. Tidak perlu secara eksplisit mendeklarasikan variabel seperti itu sebagai final, meskipun hal itu tidak akan menjadi kesalahan.
Mari kita lihat dengan sebuah contoh, kita memiliki variabel lokal i yang diinisialisasi dengan nilai 7, dengan ekspresi lambda kita mencoba mengubah nilai itu dengan menetapkan nilai baru ke i. Ini akan menghasilkan kesalahan kompiler - " Variabel lokal yang saya definisikan dalam cakupan terlampir harus final atau efektif final "
sumber
Topik terakhir yang efektif dijelaskan dalam JLS 4.12.4 dan paragraf terakhir berisi penjelasan yang jelas:
sumber
final adalah variabel yang mendeklarasikan dengan kata kunci
final
, contoh:tetap
final
melalui program.final efektif : setiap variabel atau parameter lokal yang diberi nilai hanya sekali sekarang (atau diperbarui hanya sekali). Ini mungkin tidak tetap final secara efektif melalui program. jadi ini berarti bahwa variabel final efektif mungkin kehilangan properti final efektif setelah segera saat ia ditugaskan / diperbarui setidaknya satu tugas lagi. contoh:
sumber
final
kata kunci ke deklarasi tanpa memasukkan kesalahan kompilasi, maka itu tidak final secara efektif . Ini adalah kontrapositif dari pernyataan ini: "Jika suatu variabel secara efektif final, menambahkan pengubah akhir ke deklarasi tidak akan menimbulkan kesalahan waktu kompilasi."Seperti yang dikatakan orang lain, variabel atau parameter yang nilainya tidak pernah berubah setelah diinisialisasi secara efektif bersifat final. Dalam kode di atas, jika Anda mengubah nilai
x
di kelas dalamFirstLevel
maka kompiler akan memberi Anda pesan kesalahan:sumber
Ekspresi Lambda dapat mengakses
variabel statis,
variabel instan,
parameter metode akhir yang efektif, dan
variabel lokal akhir yang efektif.
Sumber: OCP: Panduan Studi II Programmer II Java Certified Professional Java SE, Jeanne Boyarsky, Scott Selikoff
Selain itu,
Sumber: Memulai dengan Java: Dari Struktur Kontrol melalui Objek (Edisi 6), Tony Gaddis
Selain itu, jangan lupa arti
final
bahwa itu diinisialisasi tepat sekali sebelum digunakan untuk pertama kalinya.sumber
Mendeklarasikan suatu variabel
final
atau tidak mendeklarasikannyafinal
, tetapi menjaganya agar tetap final dapat menghasilkan (tergantung pada kompiler) dalam bytecode yang berbeda.Mari kita lihat contoh kecil:
Yang sesuai bytecode dari
main
metode (Java 8u161 pada Windows 64 Bit):Tabel nomor baris yang sesuai:
Seperti yang kita lihat source code di garis
12
,13
,14
tidak muncul dalam kode byte. Itu karenai
initrue
dan tidak akan mengubah keadaan itu. Dengan demikian kode ini tidak dapat dijangkau (lebih banyak dalam jawaban ini ). Untuk alasan yang sama, kode pada baris9
juga tidak ada. Keadaani
tidak harus dievaluasi karenatrue
pasti.Di sisi lain meskipun variabel
j
adalah efektif akhir itu tidak diproses dengan cara yang sama. Tidak ada optimasi yang diterapkan. Keadaanj
dievaluasi dua kali. Bytecode adalah sama terlepas darij
menjadi efektif akhir .sumber
Variabel terakhir yang efektif adalah variabel lokal yaitu:
final
Sedangkan variabel terakhir adalah variabel yaitu:
final
kata kunci.sumber
Ini tidak dimulai pada Java 8, saya menggunakan ini sejak lama. Kode ini digunakan (sebelum java 8) legal:
sumber
final
variabel yang dapat diakses, tetapi di Java 8 juga variabel yang final secara efektif .