Local variable log defined in an enclosing scope must be final or effectively final

We Are Going To Discuss About Local variable log defined in an enclosing scope must be final or effectively final. So lets Start this Java Article.

Local variable log defined in an enclosing scope must be final or effectively final

  1. Local variable log defined in an enclosing scope must be final or effectively final

    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.

  2. Local variable log defined in an enclosing scope must be final or effectively final

    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.

Solution 1

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:

  • local variables used (read) inside a lambda must act like a constant
  • you can not write to local variables!
  • or the other way round: if you need something to write to, you have to use a field of your surrounding class for example (or provide a call back method)
Advertisements

Original Author GhostCat Of This Content

Solution 2

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.

Advertisements

Original Author Kedar Mhaswade Of This Content

Solution 3

Remember method inner classes can`t modify any value from their surrounding method. Your second lambda expression in forecach is trying to access its surrounding method variable (log).

To solve this you can avoid using lambda in for each and so a simple for each and re-palace all the values in log.

        filteredRdd.map(log -> {
        for (String text:placeHolder){
            log = log.replace(text,",");
        }
        return log;
    });
Advertisements

Original Author Mr.Q Of This Content

Solution 4

In some use cases there can be a work around. The following code complains about the startTime variable not being effectively final:

List<Report> reportsBeforeTime = reports.stream()
                                        .filter(r->r.getTime().isAfter(startTime))
                                        .collect(Collectors.toList());

So, just copy the value to a final variable before passing it to lambda:

final LocalTime finalStartTime = startTime;
    List<Report> reportsBeforeTime = reports.stream()
                                            .filter(r->r.getTime().isAfter(finalStartTime))
                                            .collect(Collectors.toList());

However, If you need to change a local variable inside a lambda function, that won’t work.

Advertisements

Original Author Deb Of This Content

Conclusion

Advertisements

So This is all About This Tutorial. Hope This Tutorial Helped You. Thank You.

Also Read,

Siddharth

I am an Information Technology Engineer. I have Completed my MCA And I have 4 Year Plus Experience, I am a web developer with knowledge of multiple back-end platforms Like PHP, Node.js, Python and frontend JavaScript frameworks Like Angular, React, and Vue.

Leave a Comment