To my understanding, lambda expressions capture values, not the variables. For example, the following is a compile-time error:
for (int k = 0; k < 10; k++
In an enhanced for loop the variable is initialized every iteration. From §14.14.2 of the Java Language Specification (JLS):
...
When an enhanced
forstatement is executed, the local variable is initialized, on each iteration of the loop, to successive elements of the array orIterableproduced by the expression. The precise meaning of the enhancedforstatement is given by translation into a basicforstatement, as follows:
If the type of Expression is a subtype of
Iterable, then the translation is as follows.If the type of Expression is a subtype of
Iterablefor some type argumentX, then letIbe the typejava.util.Iterator; otherwise, letIbe the raw typejava.util.Iterator.The enhanced
forstatement is equivalent to a basicforstatement of the form:for (I #i = Expression.iterator(); #i.hasNext(); ) { {VariableModifier} TargetType Identifier = (TargetType) #i.next(); Statement }...
Otherwise, the Expression necessarily has an array type,
T[].Let
L1 ... Lmbe the (possibly empty) sequence of labels immediately preceding the enhancedforstatement.The enhanced
forstatement is equivalent to a basicforstatement of the form:T[] #a = Expression; L1: L2: ... Lm: for (int #i = 0; #i < #a.length; #i++) { {VariableModifier} TargetType Identifier = #a[#i]; Statement }...
In other words, your enhanced for loop is equivalent to:
ArrayList listOfInt = new ArrayList<>();
// add elements...
for (Iterator itr = listOfInt.iterator(); itr.hasNext(); ) {
Integer arg = itr.next();
new Thread(() -> System.out.println(arg)).start();
}
Since the variable is initialized each iteration it is effectively final (unless you modify the variable inside the loop).
In contrast, the variable in the basic for loop (k in your case) is initialized once and updated each iteration (if a "ForUpdate" is present, e.g. k++). See §14.14.1 of the JLS for more information. Since the variable is updated each iteration is is not final nor effectively final.
The need for a final or effectively final variable is mandated and explained by §15.27.2 of the JLS:
...
Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared
finalor be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.Any local variable used but not declared in a lambda body must be definitely assigned (§16 (Definite Assignment)) before the lambda body, or a compile-time error occurs.
Similar rules on variable use apply in the body of an inner class (§8.1.3). The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems. Compared to the
finalrestriction, it reduces the clerical burden on programmers.The restriction to effectively final variables includes standard loop variables, but not enhanced-
forloop variables, which are treated as distinct for each iteration of the loop (§14.14.2)....
That last sentence even explicitly mentions the difference between basic for loop variables and enhanced for loop variables.