Final vs Final Berkesan di Jawa

1. Pengenalan

Salah satu ciri paling menarik yang diperkenalkan di Java 8 adalah muktamad. Ini memungkinkan kita untuk tidak menulis pengubah akhir untuk pemboleh ubah, medan, dan parameter yang diperlakukan dan digunakan secara berkesan seperti yang terakhir.

Dalam tutorial ini, kita akan meneroka asal ciri ini dan bagaimana ia diperlakukan oleh penyusun berbanding dengan kata kunci terakhir . Selanjutnya, kami akan mencari jalan penyelesaian yang boleh digunakan mengenai kes penggunaan pemboleh ubah akhir yang bermasalah.

2. Asal Akhir Berkesan

Secara sederhana, objek atau nilai primitif adalah muktamad sekiranya kita tidak mengubah nilainya setelah inisialisasi . Sekiranya terdapat objek, jika kita tidak mengubah rujukan objek, maka ia adalah muktamad - walaupun perubahan berlaku dalam keadaan objek yang dirujuk.

Sebelum diperkenalkan, kami tidak dapat menggunakan pemboleh ubah tempatan bukan akhir dalam kelas tanpa nama . Kami masih tidak dapat menggunakan pemboleh ubah yang mempunyai lebih dari satu nilai yang diberikan kepada mereka di dalam kelas tanpa nama, kelas dalam, dan ungkapan lambda. Pengenalan ciri ini membolehkan kita tidak perlu menggunakan pengubah akhir pada pemboleh ubah yang secara efektif bersifat akhir, menjimatkan beberapa penekanan kunci.

Kelas tanpa nama adalah kelas dalaman dan mereka tidak dapat mengakses pemboleh ubah akhir atau tidak berkesan atau mengubahnya dalam ruang lingkupnya seperti yang ditentukan oleh JLS 8.1.3. Batasan yang sama berlaku untuk ungkapan lambda, kerana memiliki akses berpotensi menghasilkan masalah serentak.

3. Akhir vs Akhir Berkesan

Kaedah paling mudah untuk memahami sama ada pemboleh ubah akhir secara efektif adalah memikirkan sama ada membuang kata kunci akhir akan membolehkan kod menyusun dan menjalankan:

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

Menetapkan semula nilai atau mengubah mutasi pemboleh ubah akhir yang berkesan di atas akan menjadikan kod tidak sah di mana pun ia berlaku.

3.1. Rawatan Penyusun

JLS 4.12.4 menyatakan bahawa jika kita membuang pengubah akhir dari parameter kaedah atau pemboleh ubah tempatan tanpa memperkenalkan ralat waktu kompilasi, maka ia adalah muktamad. Lebih-lebih lagi, jika kita menambahkan kata kunci akhir pada pengisytiharan pemboleh ubah dalam program yang sah, maka ia adalah muktamad.

Penyusun Java tidak melakukan pengoptimuman tambahan untuk pemboleh ubah akhir yang berkesan, tidak seperti yang dilakukan untuk pemboleh ubah akhir .

Mari pertimbangkan contoh mudah yang menyatakan dua pemboleh ubah 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); } 

Penyusun akan mengubah kod yang dilaksanakan dalam kaedah utama di atas kepada:

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

Sebaliknya, jika kita membuang pengubah akhir , pemboleh ubah akan dianggap berkesan akhir, tetapi penyusun tidak akan menghapusnya kerana ia hanya digunakan untuk penggabungan.

4. Pengubahsuaian Atom

Secara amnya, bukan merupakan amalan yang baik untuk mengubah pemboleh ubah yang digunakan dalam ungkapan lambda dan kelas tanpa nama . Kami tidak dapat mengetahui bagaimana pemboleh ubah ini akan digunakan di dalam blok kaedah. Memutuskannya mungkin membawa hasil yang tidak dijangka dalam persekitaran multithreading.

Kami sudah mempunyai tutorial yang menerangkan amalan terbaik ketika menggunakan ungkapan lambda dan satu lagi yang menerangkan anti-corak umum ketika kami mengubahnya. Tetapi ada pendekatan alternatif yang membolehkan kita mengubah pemboleh ubah dalam kes seperti yang mencapai keselamatan benang melalui atomik.

Pakej java.util.concurrent.atomic menawarkan kelas seperti AtomicReference dan AtomicInteger . Kita boleh menggunakannya untuk mengubah secara automatik pemboleh ubah dalam ungkapan lambda:

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

5. Kesimpulan

Dalam tutorial ini, kami mengetahui perbezaan yang paling ketara antara pemboleh ubah akhir dan akhir yang berkesan. Sebagai tambahan, kami menyediakan alternatif yang selamat yang membolehkan kami mengubah pemboleh ubah di dalam fungsi lambda.