I'm playing with Java 8 and hit a basic scenario that illustrates a catch 22 where fixing one compile error causes another compile error. The scenario (which is just an example simplified from something more complex):
public static List<String> catch22(List<String> input) {
List<String> result = null;
if (input != null) {
result = new ArrayList<>(input.size());
input.forEach(e -> result.add(e)); // compile error here
}
return result;
}
I get a compile error:
Local variable result defined in an enclosing scope must be final or effectively final
If I change the first line to:
List<String> result;
I get a compile error on the last line:
The local variable result may not have been initialized
It seems like the only approach here is to pre-initialize my result to an ArrayList, which I don't want to do, or not use lambda expressions. Am I missing any other solution?
Here, i summarized some general solutions for lambdas expressions modifying method local variables.
Lambdas Expressions are actually anonymous inner classes in a concise form. When we use them in local methods we should take several constraints into consideration:
lambdas expressions(anonymous inner class) cant modify local variables of surrounding method link here they must be final or in java 8 effectively final
Unlike instance variables, local variables do not get default values and if you want to use or return them you must initialize them first
When these two constraints collide (in case of defining a lambdas in a method where lambdas modifies local variable in surrounding method), we get into trouble
solutions:
solution 1: do not modify method local variable in lambdas or use instance variables instead
solution 2: do some tricks, for example copy local variable into another one and pass that to lambdas:
public static List<String> catch22(List<String> input) {
List<String> result = null;
if (input != null) {
result = new ArrayList<>(input.size());
List<String> effectivelyFinalResult = result;
input.forEach(e -> effectivelyFinalResult.add(e));
}
return result;
}
or limit local variables scope so you dont get into trouble for not initializing them:
public static List<String> catch22(List<String> input) {
if (input != null) {
List<String> result; // result gets its value in the lambdas so it is effectively final
result = new ArrayList<>(input.size());
input.forEach(e -> result.add(e));
return result;
} else {
return null;
}
}
Push the declaration inside the block with input != null. Example:
public static List<String> catch22(List<String> input) {
if (input != null) {
List<String> result;
result = new ArrayList<>(input.size());
input.forEach(e -> result.add(e)); // compile error here
return result;
} else {
return null; // or empty list or something that suits your app
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With