Ich spiele mit Lambdas in Java 8 und bin auf die Warnung lokale Variablen, auf die von einem Lambda-Ausdruck verwiesen wird, müssen endgültig oder effektiv endgültig sein
gestoßen. Ich weiß, dass wenn ich Variablen innerhalb einer anonymen Klasse verwende, sie in der äußeren Klasse final sein müssen, aber trotzdem - was ist der Unterschied zwischen final und effektiv endgültig?
Antworten
Zu viele Anzeigen?Eine Variable ist final oder effektiv final, wenn sie einmal initialisiert wird und nie in ihrer Besitzerklasse mutiert wird. Und wir können sie nicht in Schleifen oder inneren Klassen initialisieren.
Final:
final int zahl;
zahl = 23;
Effektiv Final:
int zahl;
zahl = 34;
Hinweis: Final und Effektiv Final sind ähnlich (ihr Wert ändert sich nach der Zuweisung nicht), aber effektiv finale Variablen werden nicht mit dem Schlüsselwort
final
deklariert.
Wenn ein Lambda-Ausdruck eine zugewiesene lokale Variable aus seinem umgebenden Raum verwendet, gibt es eine wichtige Einschränkung. Ein Lambda-Ausdruck darf nur lokale Variablen verwenden, deren Wert sich nicht ändert. Diese Einschränkung wird als "Variablenerfassung" bezeichnet, die wie folgt beschrieben wird; Lambda-Ausdrücke erfassen Werte, nicht Variablen.
Die lokalen Variablen, die ein Lambda-Ausdruck verwenden kann, werden als "effektiv final" bezeichnet.
Eine effektiv endgültige Variable ist eine, deren Wert sich nach der ersten Zuweisung nicht ändert. Es ist nicht erforderlich, eine solche Variable explizit als final zu deklarieren, obwohl dies kein Fehler wäre.
Lassen Sie uns das an einem Beispiel sehen: Wir haben eine lokale Variable i, die mit dem Wert 7 initialisiert ist. Im Lambda-Ausdruck versuchen wir, diesen Wert zu ändern, indem wir i einen neuen Wert zuweisen. Dies führt zu einem Compilerfehler - "Die lokale Variable i, die in einem umgebenden Bereich definiert ist, muss endgültig oder effektiv final sein"
@FunctionalInterface
Schnittstelle IFuncInt {
int func(int num1, int num2);
public String toString();
}
Öffentliche Klasse LambdaVarDemo {
Öffentliche statische Leere main(String[] args){
int i = 7;
IFuncInt funcInt = (num1, num2) -> {
i = num1 + num2;
zurückgeben i;
};
}
}
Der Effektive Schlussthema wird in JLS 4.12.4 beschrieben und der letzte Absatz enthält eine klare Erklärung:
Wenn eine Variable effektiv final ist, führt das Hinzufügen des final-Modifiers zu ihrer Deklaration nicht zu Kompilierungsfehlern. Umgekehrt wird eine lokale Variable oder ein Parameter, der in einem gültigen Programm als final deklariert ist, effektiv final, wenn der final-Modifier entfernt wird.
final ist eine Variable, die mit dem Schlüsselwort final
deklariert wird, Beispiel:
final double pi = 3,14 ;
Es bleibt final
im gesamten Programm, nach dieser Zeile darf pi nicht mehr verändert werden.
effektiv final : jede lokale Variable oder Parameter, die aktuell nur einmal einen Wert zugewiesen bekommt (oder nur einmal aktualisiert wird). Es bleibt möglicherweise nicht im gesamten Programm effektiv final. Das bedeutet, dass eine effektiv final Variable ihre Eigenschaft als effektiv final verlieren kann, sobald sie mindestens eine weitere Zuweisung direkt nachdem sie zugewiesen/aktualisiert wurde, bekommt. Beispiel:
class EffectivelyFinal {
public static void main(String[] args) {
calculate(124,53);
}
public static void calculate( int operand1, int operand2){
int rem = 0; // operand1, operand2 und rem sind hier effektiv final
rem = operand1%2 // rem verliert hier seine Eigenschaft als effektiv final, weil es seine zweite Zuweisung bekommt
// operand1, operand2 sind immer noch effektiv final hier
class operators{
void setNum(){
operand1 = operand2%2; // operand1 verliert hier seine Eigenschaft als effektiv final, weil es seine zweite Zuweisung bekommt
}
int add(){
return rem + operand2; // kompiliert nicht, da rem nicht effektiv final ist
}
int multiply(){
return rem * operand1; // kompiliert nicht, da sowohl rem als auch operand1 nicht effektiv final sind
}
}
}
}
public class LambdaScopeTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) {
// Die folgende Anweisung führt dazu, dass der Compiler den Fehler
// "lokale Variablen, auf die in einem Lambda-Ausdruck verwiesen wird,
// müssen final oder effektiv final sein" in der Anweisung A erzeugt:
//
// x = 99;
}
}
}
Wie andere bereits gesagt haben, ist eine Variable oder Parameter, dessen Wert nie nach der Initialisierung geändert wird, effektiv final. Im obigen Code, wenn Sie den Wert von x
in der inneren Klasse FirstLevel
ändern, wird der Compiler Ihnen die Fehlermeldung anzeigen:
Lokale Variablen, auf die in einem Lambda-Ausdruck verwiesen wird, müssen final oder effektiv final sein.