0

I am using Vert.x after working with Node.js for a few years and am trying to replicate some of the functionality we'd see in require('async')

package huru.util;

import java.util.ArrayList;
import java.util.List;

interface AsyncCallback {
  public void cb(Object e, Object v);
}

interface AsyncTask {
  public void run(AsyncCallback cb);
}

interface FinalCallback {
  public void run(Object e, List<Object> v);
}

public class Async {

  static void Parallel (List<AsyncTask> tasks, FinalCallback f) {

    List<Object> results = new ArrayList<Object>();
    int count = 0;

    for(int i = 0; i < tasks.size(); i++){

        tasks.get(i).run((e,v) -> {

          if(e != null){
            f.run(e, null);
            return;
          }

          count++;  // ! here, count needs to be final ??
          results.set(i,v);  

          if(count == tasks.size()){
               f.run(null, results);
          }

        });

    }

  }

}

the above is getting there, but I get this error:

Variable used in lambda expression should be final or effectively final

I assume it's a similar problem that we see in JS where the value of i might change as the loop continues.

Anyone know how to mitigate this one? Wrapping it in a self-invoking function would be how to do this with JS.

enter image description here

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • Hmmm it's been awhile since I did some Java, isn't i available in the scope? – Alexander Mills Jan 28 '19 at 08:31
  • @AlexanderMills - It's as you said in your question: `i` may change, and the lambda isn't allowed to close over a variable that may change. You could declare a variable within the loop body's scope and copy `i` to it, then use that variable (since it won't change). – T.J. Crowder Jan 28 '19 at 08:36
  • 1
    (Nice one, BTW, putting the MCVE in the question!) – T.J. Crowder Jan 28 '19 at 08:37
  • Err, make it `final`? Is this such a mystery? – user207421 Jan 28 '19 at 08:44
  • @T.J.Crowder I updated the question, I need to use a counter within the lambda... – Alexander Mills Jan 28 '19 at 08:49
  • @user207421 you lack imagination, try answering the question given the update, using a counter. – Alexander Mills Jan 28 '19 at 08:51
  • @T.J.Crowder how can I petition to reopen the question? – Alexander Mills Jan 28 '19 at 08:52
  • 1
    @AlexanderMills - The updated question is also a duplicate. The solution in that situation is to (again) give the lambda a final (or effectively final) value to close over: An object reference. Then make the counter an instance member of that object. :-) So `Counter c = new Counter();` and `c.incrementValue();` in the lambda and `c.getValue()` when you need the current value. (Sometimes you see people abusing arrays for this: `int[] c = new int[1];` and then `++c[0];`. But... – T.J. Crowder Jan 28 '19 at 08:56
  • Thanks different solution using the object wrapper, but that should work I guess – Alexander Mills Jan 28 '19 at 08:57
  • It's pretty much how you do it. The variables the lambda uses have to be final (or effectively final). I remember the first time I ran into this situation and found the answer and went "Oh, that's so...obvious...and yet, seems like cheating." :-) – T.J. Crowder Jan 28 '19 at 08:58
  • Yeah I am not sure why primitives have to be final but objects don't but who knows – Alexander Mills Jan 28 '19 at 09:00

0 Answers0