Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the non final loop variable inside a lambda expression

I'm trying to execute 100 tasks all in parallel via executors and runnable, the task needs to use the loop variable:

for (int i = 0; i < 100; i++) {
   executor.execute(() -> {
     doSomething(String.format("Need task number %d done", i));
   }
  });
}

I get a squiggly under 'i' saying - Variable used in lambda expression should be effectively final.

A loop variable, as far as I'm aware, cannot be made final or effectively final, since it is being changed with each iteration. I found a simple workaround,

for (int i = 0; i < 100; i++) {
   int index = i;
   executor.execute(() -> {
     doSomething(String.format("Need task number %d done", index));
   }
 });
}

This doesn't seem the most effective solution to me, declaring a new variable at every iteration. Is there a better way of doing this?

like image 971
Siddhartha Avatar asked Sep 11 '15 23:09

Siddhartha


People also ask

Can we use Non final variable in lambda expression?

A lambda expression can use a local variable in outer scopes only if they are effectively final.

Why do variables in lambda need to be final?

Forcing the variable to be final avoids giving the impression that incrementing start inside the lambda could actually modify the start method parameter.

How do you use local variables in lambda expression?

A lambda expression can't define any new scope as an anonymous inner class does, so we can't declare a local variable with the same which is already declared in the enclosing scope of a lambda expression. Inside lambda expression, we can't assign any value to some local variable declared outside the lambda expression.

Can we declare variable in lambda expression?

Variable defined by the enclosing scope of a lambda expression are accessible within the lambda expression. For example, a lambda expression can use an instance or static variable defined by its enclosing class.


1 Answers

Is there a better way of doing this?

I doubt it. Your solution looks fine to me, but if you want you can rewrite it into possibly clearer code like:

IntStream.range(0, 100).forEach(
    i -> executor.execute(
        () -> doSomething(String.format("Need task number %d done", i))
    )
);
like image 130
Pshemo Avatar answered Oct 19 '22 12:10

Pshemo