I'm new to lambda and Java8. I'm facing following error.
Local variable log defined in an enclosing scope must be final or effectively final
public JavaRDD<String> modify(JavaRDD<String> filteredRdd) { filteredRdd.map(log -> { placeHolder.forEach(text -> { //error comes here log = log.replace(text, ","); }); return log; }); return null; }
The local variables that a lambda expression may use are referred to as “effectively final”. An effectively final variable is one whose value doesn't change after it's first assigned. There is no need to explicitly declare such a variable as final, although doing so would not be an error.
Forcing the variable to be final avoids giving the impression that incrementing start inside the lambda could actually modify the start method parameter.
Since it is a rule in Java programming language that variable in an enclosing scope can't be change in inner class or lambda expression, so you can't change the value of the variable.
In simple terms, objects or primitive values are effectively final if we do not change their values after initialization. In the case of objects, if we do not change the reference of an object, then it is effectively final — even if a change occurs in the state of the referenced object.
The message says exactly what the problem is: your variable log must be final (that is: carry the keyword final) or be effectively final (that is: you only assign a value to it once outside of the lambda). Otherwise, you can't use that variable within your lambda statement.
But of course, that conflicts with your usage of log. The point is: you can't write to something external from within the lambda ... so you have to step back and look for other ways for whatever you intend to do.
In that sense: just believe the compiler.
Beyond that, there is one core point to understand: you can not use a local variable that you can write to. Local variables are "copied" into the context of the lambda at runtime, and in order to achieve deterministic behavior, they can only be read, and should be constants.
If your use case is to write to some object, then it should be a field of your enclosing class for example!
So, long story short:
The reason for this limitation is the same as the reason for the Java language feature that local variables accessed from within (anonymous) inner classes must be (effectively) final.
This answer by rgettman gets into the details of it. rgettman explains the limitations in clear detail and I link to that answer because the behavior of lambda expressions should be same as that of anonymous inner classes. Note that such limitation does not exist for class or instance variables, however. The main reason for this is slightly complicated and I couldn't explain it better than what Roedy Green does it here. Copying here only so it is at one place:
The rule is anonymous inner classes may only access final local variables of the enclosing method. Why? Because the inner class’s methods may be invoked later, long after the method that spawned it has terminated, e.g. by an AWT (Advanced Windowing Toolkit) event. The local variables are long gone. The anonymous class then must work with flash frozen copies of just the ones it needs squirreled away covertly by the compiler in the anonymous inner class object. You might ask, why do the local variables have to be final? Could not the compiler just as well take a copy of non-final local variables, much the way it does for a non-final parameters? If it did so, you would have two copies of the variable. Each could change independently, much like caller and callee’s copy of a parameter, however you would use the same syntax to access either copy. This would be confusing. So Sun insisted the local be final. This makes irrelevant that there are actually two copies of it.
The ability for an anonymous class to access the caller’s final local variables is really just syntactic sugar for automatically passing in some local variables as extra constructor parameters. The whole thing smells to me of diluted eau de kludge.
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