Finale versus effectief Finale in Java

1. Inleiding

Een van de meest interessante functies die in Java 8 zijn geïntroduceerd, is in feite definitief. Het staat ons toe om het laatste modificator voor variabelen, velden en parameters die effectief worden behandeld en gebruikt als de laatste.

In deze tutorial zullen we de functies van deze functie verkennen origin en hoe het wordt behandeld door de compiler in vergelijking met de laatste trefwoord. Verder zullen we een oplossing onderzoeken om te gebruiken met betrekking tot een problematisch gebruik van effectief eindvariabelen.

2. Effectief definitieve oorsprong

In simpele termen, objecten of primitieve waarden zijn in feite definitief als we hun waarden na initialisatie niet wijzigen. Als we in het geval van objecten de referentie van een object niet wijzigen, is deze in feite definitief - zelfs als er een verandering optreedt in de toestand van het object waarnaar wordt verwezen.

Voorafgaand aan de introductie, we konden geen niet-definitieve lokale variabele gebruiken in een anonieme klasse. We kunnen nog steeds geen variabelen gebruiken waaraan meer dan één waarde is toegewezen binnen anonieme klassen, innerlijke klassen en lambda-expressies. Door de introductie van deze functie hoeven we de laatste modifier op variabelen die effectief definitief zijn, wat ons een paar toetsaanslagen bespaart.

Anonieme klassen zijn innerlijke klassen en ze hebben geen toegang tot niet-definitieve of niet-effectief definitieve variabelen of ze kunnen ze muteren in hun omringende scopes zoals gespecificeerd door JLS 8.1.3. Dezelfde beperking is van toepassing op lambda-expressies, omdat toegang hebben mogelijk gelijktijdigheidsproblemen kan veroorzaken.

3. Finale versus effectief finale

De eenvoudigste manier om erachter te komen of een laatste variabele effectief definitief is, is door na te denken of de laatste trefwoord zou de code toestaan ​​om te compileren en uit te voeren:

@FunctionalInterface openbare interface FunctionalInterface {void testEffectivelyFinal (); standaard ongeldige test () {int effectiefFinalInt = 10; FunctionalInterface functionalInterface = () -> System.out.println ("Waarde van effectieve variabele is:" + effectiefFinalInt); }} 

Het opnieuw toewijzen van een waarde of het muteren van de bovenstaande feitelijke laatste variabele zou de code ongeldig maken, ongeacht waar deze voorkomt.

3.1. Compiler-behandeling

JLS 4.12.4 stelt dat als we het laatste modifier van een methodeparameter of een lokale variabele zonder compilatietijdfouten te introduceren, dan is het in feite definitief. Bovendien, als we de laatste trefwoord naar de declaratie van een variabele in een geldig programma, dan is het in feite definitief.

De Java-compiler doet geen aanvullende optimalisatie voor effectieve eindvariabelen, in tegenstelling tot laatste variabelen.

Laten we eens kijken naar een eenvoudig voorbeeld dat twee declareert laatste String variabelen, maar gebruikt ze alleen voor aaneenschakeling:

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

De compiler zou de code wijzigen die wordt uitgevoerd in de hoofd bovenstaande methode om:

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

Aan de andere kant, als we de laatste modificatoren, zouden de variabelen als definitief beschouwd worden, maar de compiler zal ze niet verwijderen omdat ze alleen worden gebruikt voor aaneenschakeling.

4. Atoommodificatie

Over het algemeen, het is geen goede gewoonte om variabelen te wijzigen die worden gebruikt in lambda-expressies en anonieme klassen. We kunnen niet weten hoe deze variabelen zullen worden gebruikt in methodeblokken. Het muteren ervan kan leiden tot onverwachte resultaten in multithreading-omgevingen.

We hebben al een tutorial waarin de best practices worden uitgelegd bij het gebruik van lambda-expressies en een andere waarin algemene antipatronen worden uitgelegd wanneer we ze aanpassen. Maar er is een alternatieve benadering waarmee we variabelen kunnen wijzigen in dergelijke gevallen die draadveiligheid bereiken door atomiciteit.

Het pakket java.util.concurrent.atomic biedt lessen aan zoals AtomicReference en AtomicInteger. We kunnen ze gebruiken om variabelen in lambda-expressies atomair te wijzigen:

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

5. Conclusie

In deze tutorial hebben we geleerd over de meest opvallende verschillen tussen laatste en effectief laatste variabelen. Bovendien hebben we een veilig alternatief geboden waarmee we variabelen binnen lambda-functies kunnen wijzigen.