Final vs Effectively Final i Java

1. Introduksjon

En av de mest interessante funksjonene som ble introdusert i Java 8 er faktisk endelig. Det lar oss ikke skrive endelig modifikator for variabler, felt og parametere som behandles effektivt og brukes som endelige.

I denne opplæringen vil vi utforske denne funksjonen opprinnelse og hvordan den behandles av kompilatoren sammenlignet med endelig nøkkelord. Videre vil vi utforske en løsning å bruke angående et problematisk brukstilfelle av effektivt endelige variabler.

2. Effektivt sluttopprinnelse

For å si det enkelt, objekter eller primitive verdier er faktisk endelige hvis vi ikke endrer verdiene deres etter initialisering. Når det gjelder objekter, hvis vi ikke endrer referansen til et objekt, så er det effektivt endelig - selv om det skjer en endring i tilstanden til det refererte objektet.

Før introduksjonen, vi kunne ikke bruke en ikke-endelig lokal variabel i en anonym klasse. Vi kan fortsatt ikke bruke variabler som har tildelt mer enn én verdi i anonyme klasser, indre klasser og lambdauttrykk. Innføringen av denne funksjonen gjør at vi ikke trenger å bruke endelig modifikator på variabler som faktisk er endelige, og sparer oss noen tastetrykk.

Anonyme klasser er indre klasser, og de kan ikke få tilgang til ikke-endelige eller ikke-effektive endelige variabler eller mutere dem i deres vedlagte omfang som spesifisert i JLS 8.1.3. Den samme begrensningen gjelder lambdauttrykk, ettersom tilgang kan potensielt gi problemer med samtidighet.

3. Final vs Effektivt Final

Den enkleste måten å forstå om en endelig variabel faktisk er endelig, er å tenke om å fjerne endelig nøkkelord vil tillate koden å kompilere og kjøre:

@FunctionalInterface offentlig grensesnitt FunctionalInterface {void testEffectivelyFinal (); standard ugyldighetstest () {int effectiveFinalInt = 10; FunctionalInterface functionalInterface = () -> System.out.println ("Verdien av effektiv variabel er:" + effektivFinalInt); }} 

Hvis du tildeler en verdi på nytt eller muterer den ovennevnte endelige variabelen, vil koden bli ugyldig uansett hvor den forekommer.

3.1. Kompilatorbehandling

JLS 4.12.4 sier at hvis vi fjerner endelig modifiser fra en metodeparameter eller en lokal variabel uten å innføre kompileringstidsfeil, så er den effektivt endelig. Videre, hvis vi legger til endelig nøkkelord til en variabels erklæring i et gyldig program, så er det effektivt endelig.

Java-kompilatoren gjør ikke ytterligere optimalisering for effektivt endelige variabler, i motsetning til det gjør for endelig variabler.

La oss vurdere et enkelt eksempel som erklærer to siste streng variabler, men bruker dem bare for sammenkobling:

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

Kompilatoren ville endre koden som ble utført i hoved- metoden ovenfor for å:

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

På den andre siden, hvis vi fjerner endelig modifikatorer, ville variablene bli betraktet som endelige, men kompilatoren vil ikke fjerne dem siden de bare brukes til sammenføyning.

4. Atomic Modification

Som regel, det er ikke god praksis å endre variabler som brukes i lambdauttrykk og anonyme klasser. Vi kan ikke vite hvordan disse variablene skal brukes i metodeblokker. Mutering av dem kan føre til uventede resultater i flertrådingsmiljøer.

Vi har allerede en veiledning som forklarer de beste fremgangsmåtene når du bruker lambdauttrykk, og en annen som forklarer vanlige antimønstre når vi endrer dem. Men det er en alternativ tilnærming som lar oss modifisere variabler i slike tilfeller som oppnår trådsikkerhet gjennom atomicitet.

Pakken java.util.concurrent.atomic tilbyr klasser som AtomicReference og AtomicInteger. Vi kan bruke dem til å atomisk modifisere variabler i lambdauttrykk:

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

5. Konklusjon

I denne opplæringen lærte vi om de mest bemerkelsesverdige forskjellene mellom endelig og effektivt endelige variabler. I tillegg ga vi et trygt alternativ som lar oss endre variabler i lambdafunksjoner.


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