Konečné vs efektívne konečné v Jave

1. Úvod

Jedna z najzaujímavejších funkcií zavedených v prostredí Java 8 je skutočne konečná. Umožňuje nám to nenapísať konečné modifikátor pre premenné, polia a parametre, ktoré sú efektívne spracované a použité ako konečné.

V tomto tutoriáli preskúmame funkcie tejto funkcie pôvod a ako s ním zaobchádza kompilátor v porovnaní s pôvodom konečné kľúčové slovo. Ďalej preskúmame riešenie, ktoré sa má použiť, pokiaľ ide o problémový prípad použitia efektívne finálnych premenných.

2. Účinne konečný pôvod

Jednoducho povedané objekty alebo primitívne hodnoty sú skutočne konečné, ak po inicializácii ich hodnoty nezmeníme. Pokiaľ v prípade objektov nezmeníme referenciu objektu, potom je to skutočne konečné - aj keď dôjde k zmene stavu referencovaného objektu.

Pred jeho zavedením v anonymnej triede sme nemohli použiť nedokončenú lokálnu premennú. Stále nemôžeme používať premenné, ktoré majú vo svojich anonymných triedach, vnútorných triedach a výrazoch lambda priradených viac ako jednu hodnotu. Zavedenie tejto funkcie nám umožňuje, aby sme nemuseli používať konečné modifikátor premenných, ktoré sú efektívne konečné, čo nám ušetrí niekoľko stlačených klávesov.

Anonymné triedy sú vnútorné triedy a nemôžu získať prístup k premenným, ktoré nie sú konečné alebo nie sú v konečnom dôsledku, alebo ich mutovať v priloženom rozsahu, ako je špecifikované v JLS 8.1.3. Rovnaké obmedzenie platí pre výrazy lambda, pretože prístup môže potenciálne spôsobiť problémy so súbežnosťou.

3. Konečné vs efektívne konečné

Najjednoduchší spôsob, ako pochopiť, či je konečná premenná skutočne konečná, je premýšľať, či je odstránená konečné kľúčové slovo by umožnilo kódu skompilovať a spustiť:

@FunctionalInterface verejné rozhranie FunctionalInterface {void testEffectivelyFinal (); predvolený test neplatnosti () {int efektívneFinalInt = 10; FunctionalInterface functionalInterface = () -> System.out.println ("Hodnota efektívne premennej je:" + efektívneFinalInt); }} 

Opätovné priradenie hodnoty alebo mutácia účinnej výslednej premennej spôsobí, že bude kód neplatný bez ohľadu na to, kde k nemu dôjde.

3.1. Spracovanie kompilátora

JLS 4.12.4 uvádza, že ak odstránime konečné modifikátor z parametra metódy alebo lokálnej premennej bez zavedenia chýb pri kompilácii, potom je skutočne konečný. Navyše, ak pridáme konečné kľúčové slovo k deklarácii premennej v platnom programe, potom je skutočne konečné.

Kompilátor Java nerobí dodatočnú optimalizáciu pre efektívne konečné premenné, na rozdiel od toho robí konečné premenné.

Uvažujme o jednoduchom príklade, ktorý deklaruje dva posledný reťazec premenné, ale používa ich iba na zreťazenie:

public static void main (String [] args) {final String ahoj = "ahoj"; final String world = "svet"; Skúška reťazcom = ahoj + "" + svet; System.out.println (test); } 

Kompilátor by zmenil kód vykonaný v hlavný vyššie uvedená metóda:

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

Na druhej strane, ak odstránime konečné modifikátory, premenné by sa považovali za skutočne konečné, ale kompilátor ich neodstráni pretože sa používajú iba na zreťazenie.

4. Atómová modifikácia

Spravidla nie je dobrým zvykom upravovať premenné používané vo výrazoch lambda a v anonymných triedach. Nemôžeme vedieť, ako sa tieto premenné použijú vo vnútri blokov metód. Ich mutácia môže viesť k neočakávaným výsledkom v prostrediach s viacerými vláknami.

Už máme výukový program vysvetľujúci najlepšie postupy pri používaní výrazov lambda a ďalší, ktorý vysvetľuje bežné anti-vzory, keď ich upravujeme. Existuje však alternatívny prístup, ktorý nám umožňuje upravovať premenné v takých prípadoch, ktoré zaisťujú bezpečnosť vlákien prostredníctvom atomicity.

Balík java.util.concurrent.atomic ponúka kurzy ako napr Atómová referencia a AtomicInteger. Môžeme ich použiť na atómovú modifikáciu premenných vo vnútri výrazov lambda:

public static void main (String [] args) {AtomicInteger efektívneFinalInt = nový AtomicInteger (10); FunctionalInterface FunkčnéInterface = efektívneFinalInt :: incrementAndGet; }

5. Záver

V tomto tutoriáli sme sa dozvedeli o najvýznamnejších rozdieloch medzi nimi konečné a efektívne konečné premenné. Okrem toho sme poskytli bezpečnú alternatívu, ktorá nám umožňuje upravovať premenné vo vnútri funkcií lambda.


$config[zx-auto] not found$config[zx-overlay] not found