Difference between final and effectively final
... starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.
For example, suppose that the variable numberLength
is not declared final, and you add the marked assignment statement in the PhoneNumber
constructor:
public class OutterClass {
int numberLength; // <== not *final*
class PhoneNumber {
PhoneNumber(String phoneNumber) {
numberLength = 7; // <== assignment to numberLength
String currentNumber = phoneNumber.replaceAll(
regularExpression, "");
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}
...
}
...
}
Because of this assignment statement, the variable numberLength is not effectively final anymore. As a result, the Java compiler generates an error message similar to "local variables referenced from an inner class must be final or effectively final" where the inner class PhoneNumber tries to access the numberLength variable:
http://codeinventions.blogspot.in/2014/07/difference-between-final-and.html
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
Why does variables in lambdas have to be final or effectively final?
It is related to multi-thread programming.
Local variables in Java have until now been immune to race conditions
and visibility problems because they are accessible only to the thread
executing the method in which they are declared. But a lambda can be
passed from the thread that created it to a different thread, and that
immunity would therefore be lost if the lambda, evaluated by the
second thread, were given the ability to mutate local variables. - Source
Effectively final vs final - Different behavior
First of all, we are talking about local variables only. Effectively final does not apply to fields. This is important, since the semantics for final
fields are very distinct and are subject to heavy compiler optimizations and memory model promises, see $17.5.1 on the semantics of final fields.
On a surface level final
and effectively final
for local variables are indeed identical. However, the JLS makes a clear distinction between the two which actually has a wide range of effects in special situations like this.
Premise
From JLS§4.12.4 about final
variables:
A constant variable is a
final
variable of primitive type or type String that is initialized with a constant expression (§15.29). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1), reachability (§14.22), and definite assignment (§16.1.1).
Since int
is primitive, the variable a
is such a constant variable.
Further, from the same chapter about effectively final
:
Certain variables that are not declared final are instead considered effectively final: ...
So from the way this is worded, it is clear that in the other example, a
is not considered a constant variable, as it is not final, but only effectively final.
Behavior
Now that we have the distinction, lets lookup what is going on and why the output is different.
You are using the conditional operator ? :
here, so we have to check its definition. From JLS§15.25:
There are three kinds of conditional expressions, classified according to the second and third operand expressions: boolean conditional expressions, numeric conditional expressions, and reference conditional expressions.
In this case, we are talking about a numeric conditional expressions, from JLS§15.25.2:
The type of a numeric conditional expression is determined as follows:
And that is the part where the two cases get classified differently.
effectively final
The version that is effectively final
is matched by this rule:
Otherwise, general numeric promotion (§5.6) is applied to the second and third operands, and the type of the conditional expression is the promoted type of the second and third operands.
Which is the same behavior as if you would do 5 + 'd'
, i.e. int + char
, which results in int
. See JLS§5.6
Numeric promotion determines the promoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:
[...]
Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:
In a numeric choice context, the following rules apply:
If any expression is of type
int
and is not a constant expression (§15.29), then the promoted type isint
, and other expressions that are not of typeint
undergo widening primitive conversion toint
.
So everything is promoted to int
as a
is an int
already. That explains the output of 97
.
final
The version with the final
variable is matched by this rule:
If one of the operands is of type
T
whereT
isbyte
,short
, orchar
, and the other operand is a constant expression (§15.29) of typeint
whose value is representable in typeT
, then the type of the conditional expression isT
.
The final variable a
is of type int
and a constant expression (because it is final
). It is representable as char
, hence the outcome is of type char
. That concludes the output a
.
String example
The example with the string equality is based on the same core difference, final
variables are treated as constant expression/variable, and effectively final
is not.
In Java, string interning is based on constant expressions, hence
"a" + "b" + "c" == "abc"
is true
as well (dont use this construct in real code).
See JLS§3.10.5:
Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.29) - are "interned" so as to share unique instances, using the method
String.intern
(§12.5).
Easy to overlook as it is primarily talking about literals, but it actually applies to constant expressions as well.
What is the benefit being able to use effectively final variables in Java 8 lambda expressions
The simple answer is, since there is no difference between final
and “effectively final” variables, besides the keyword final
in their declaration, the only purpose is to allow omitting the final
keyword.
But this might have more impact than you are aware of.
For a lambda expression, the entire declaration of the parameter(s) can be simplified as in x -> x+1
. Now consider nested lambda expressions like: x -> y -> x+y
and the visual clutter which would be created if we were enforce to add a final
declaration to the x
parameter here.
Since there is no Java syntax to declare a variable as final
without specifying its type it would either require the specification to add an even more complex construct to the language or enforce us to add final
and a type declaration to the parameter turning the simple expression x -> y -> x+y
into (final double x) -> y -> x+y
.
The main goal was to provide a simplification to the Java programmer (as far as this is possible when adding a new programming language feature). Surely it doesn’t offer any feature to the language for solving problems which couldn’t be solved before without it (this holds for the entire lambda feature), but there is a notable gain in expressiveness not only because you can omit final
modifiers but it helps. It works together with the improved type inference, new programming APIs and, of course, lambda expressions and method references.
Variable used in lambda expression should be final or effectively final
A final
variable means that it can be instantiated only one time.
in Java you can't reassign non-final local variables in lambda as well as in anonymous inner classes.
You can refactor your code with the old for-each loop:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
try {
for(Component component : cal.getComponents().getComponents("VTIMEZONE")) {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(calTz==null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
Even if I don't get the sense of some pieces of this code:
- you call a
v.getTimeZoneId();
without using its return value - with the assignment
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
you don't modify the originally passedcalTz
and you don't use it in this method - You always return
null
, why don't you setvoid
as return type?
Hope also these tips helps you to improve.
Java 8 variable should be final or effectively final issue
You could avoid the problem by using the lambda expression to return true or false if there are any names that are not null, and assign the result to your boolean.
Something like this:
boolean hasAnyWithNames = list.stream().anyMatch(c -> c.getName() != null);
The choice "bool" is not a good one for variable name by the way.
Edit:
- Replaced Boolean with base type per comment.
- Used anyMatch() instead of filter() count per comment
Thanks
What does a variable being effectively final mean?
Effectively final means that it is never changed after getting the initial value.
A simple example:
public void myMethod() {
int a = 1;
System.out.println("My effectively final variable has value: " + a);
}
Here, a
is not declared final, but it is considered effectively final since it is never changed.
Starting with Java 8, this can be used in the following way:
public void myMethod() {
int a = 1;
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("My effectively final variable has value: " + a);
}
};
}
In Java 7 and earlier versions, a
had to be declared final
to be able to be used in an local class like this, but from Java 8 it is enough that it is effectively final.
Are the effectively final variables interpreted as final by compiler in Java 8?
Does compiler in java 8 interpret effectively final variables as final variables and later, in runtime use it as final?
The answer will be yes in both cases.
The reason for the latter is that the class file format does not provide a way to say whether a local variable is declared as final
. Therefore, if the JIT compiler is going to optimize based on finality, the finality must be inferred from what the bytecodes of a method actually do; i.e. effective finality.
Related Topics
How to Find a Button Source in Awt (Calculator Homework)
Java.Net.Socketexception: Connection Reset
How to Format the Day of the Month to Say "11Th", "21St" or "23Rd" (Ordinal Indicator)
Best Implementation For Hashcode Method For a Collection
How to Make a JPA Onetoone Relation Lazy
Simplest Way to Read Json from a Url in Java
Why Is There No Sortedlist in Java
Getting a File'S Md5 Checksum in Java
What's the Reason I Can't Create Generic Array Types in Java
Difference Between Declaring Variables Before or in Loop