Final vs Efektif Final di Java

1. Perkenalan

Salah satu fitur paling menarik yang diperkenalkan di Java 8 adalah final yang efektif. Ini memungkinkan kita untuk tidak menulis pengubah akhir untuk variabel, bidang, dan parameter yang secara efektif diperlakukan dan digunakan seperti yang terakhir.

Dalam tutorial ini, kita akan menjelajahi asal fitur ini dan bagaimana itu diperlakukan oleh compiler dibandingkan dengan kata kunci terakhir . Selanjutnya, kita akan mengeksplorasi solusi untuk digunakan terkait kasus penggunaan yang bermasalah dari variabel akhir yang efektif.

2. Asal Akhir Secara Efektif

Dalam istilah sederhana, objek atau nilai primitif secara efektif final jika kita tidak mengubah nilainya setelah inisialisasi . Dalam kasus objek, jika kita tidak mengubah referensi suatu objek, maka itu secara efektif final - bahkan jika perubahan terjadi dalam status objek yang direferensikan.

Sebelum pengenalannya, kami tidak dapat menggunakan variabel lokal non-final dalam kelas anonim . Kami masih tidak dapat menggunakan variabel yang memiliki lebih dari satu nilai yang ditugaskan padanya di dalam kelas anonim, kelas dalam, dan ekspresi lambda. Pengenalan fitur ini memungkinkan kita untuk tidak perlu menggunakan pengubah terakhir pada variabel yang secara efektif final, sehingga kita tidak perlu menekan beberapa tombol.

Kelas-kelas anonim adalah kelas-dalam dan mereka tidak dapat mengakses variabel non-final atau non-efektif-final atau memutasinya dalam cakupan tertutupnya seperti yang ditentukan oleh JLS 8.1.3. Batasan yang sama berlaku untuk ekspresi lambda, karena memiliki akses berpotensi menghasilkan masalah konkurensi.

3. Final vs Efektif Final

Cara termudah untuk memahami apakah variabel final secara efektif final adalah dengan memikirkan apakah menghapus kata kunci final akan memungkinkan kode untuk dikompilasi dan dijalankan:

@FunctionalInterface public interface FunctionalInterface { void testEffectivelyFinal(); default void test() { int effectivelyFinalInt = 10; FunctionalInterface functionalInterface = () -> System.out.println("Value of effectively variable is : " + effectivelyFinalInt); } } 

Menetapkan kembali nilai atau mengubah variabel akhir yang efektif di atas akan membuat kode tidak valid di mana pun itu terjadi.

3.1. Perawatan Penyusun

JLS 4.12.4 menyatakan bahwa jika kita menghapus pengubah akhir dari parameter metode atau variabel lokal tanpa memasukkan kesalahan waktu kompilasi, maka itu secara efektif final. Selain itu, jika kita menambahkan kata kunci terakhir ke deklarasi variabel dalam program yang valid, maka itu secara efektif final.

Compiler Java tidak melakukan pengoptimalan tambahan untuk variabel final yang efektif, tidak seperti yang dilakukannya untuk variabel final .

Mari pertimbangkan contoh sederhana yang mendeklarasikan dua variabel String terakhir tetapi hanya menggunakannya untuk penggabungan:

public static void main(String[] args) { final String hello = "hello"; final String world = "world"; String test = hello + " " + world; System.out.println(test); } 

Kompiler akan mengubah kode yang dieksekusi dalam metode utama di atas menjadi:

public static void main(String[] var0) { String var1 = "hello world"; System.out.println(var1); }

Di sisi lain, jika kita menghapus pengubah terakhir , variabel akan dianggap final secara efektif, tetapi compiler tidak akan menghapusnya karena hanya digunakan untuk penggabungan.

4. Modifikasi Atom

Secara umum, memodifikasi variabel yang digunakan dalam ekspresi lambda dan kelas anonim bukanlah praktik yang baik . Kita tidak dapat mengetahui bagaimana variabel ini akan digunakan di dalam blok metode. Memutasikannya dapat menyebabkan hasil yang tidak terduga dalam lingkungan multithreading.

Kami sudah memiliki tutorial yang menjelaskan praktik terbaik saat menggunakan ekspresi lambda dan tutorial lain yang menjelaskan anti-pola umum saat kami memodifikasinya. Tetapi ada pendekatan alternatif yang memungkinkan kita untuk memodifikasi variabel dalam kasus seperti itu yang mencapai keamanan benang melalui atomicity.

Paket java.util.concurrent.atomic menawarkan kelas-kelas seperti AtomicReference dan AtomicInteger . Kita dapat menggunakannya untuk mengubah variabel secara atom di dalam ekspresi lambda:

public static void main(String[] args) { AtomicInteger effectivelyFinalInt = new AtomicInteger(10); FunctionalInterface functionalInterface = effectivelyFinalInt::incrementAndGet; }

5. Kesimpulan

Dalam tutorial ini, kita belajar tentang perbedaan yang paling mencolok antara akhir variabel dan efektif final. Selain itu, kami menyediakan alternatif aman yang memungkinkan kami memodifikasi variabel di dalam fungsi lambda.