1

I have this code that works fine:

String name = "Oscar";
CompletableFuture.runAsync(() -> doX(name));

Now I need to add some logic to the name variable:

String name = "Oscar";
if (x){
  name = "Tiger";
}
CompletableFuture.runAsync(() -> doX(name));

But now the compiler complains about Variable used in lambda expression should be final or effectively final

I understand from posts like this one that the name must be final or effectively final, but I wonder if there is a way to write the code differently in order to enable the logic on the name variable

riorio
  • 6,500
  • 7
  • 47
  • 100
  • 3
    If the code is indeed exactly as you wrote it, you could write `String name = x ? "Tiger" : "Oscar";` - this will make for a single initializer. But if the logic is more complicated, this may not work. – RealSkeptic Feb 06 '19 at 10:52
  • 3
    Or possibly copy it into another variable to make it final as well. – Naman Feb 06 '19 at 10:58
  • or worst,should not used, Use `String[] name`, and in lambda user `name[0]`. – dkb Feb 06 '19 at 10:59
  • `CompletableFuture.completedFuture(name) .thenApplyAsync(this::doX)` use `ClassName::doX` if `doX` is `static`, use `thenAcceptAsync` if `doX` is `void`. – Holger Feb 08 '19 at 19:59

3 Answers3

2

You can use Conditional Operator, something like this:

        boolean condition = true;
        String name = condition ? "Tiger" : "Oscar";
        CompletableFuture.runAsync(() -> System.out.println(name));

Or using if statements:

 boolean condition = true;
    final String name;
    if(condition) {
        name = "Tiger";
    }else {
        name = "Oscar";
    }
    CompletableFuture.runAsync(() -> System.out.println(name));
HRgiger
  • 2,750
  • 26
  • 37
  • You can not change the value of a final variable. name = "Tiger" will not work. – vavasthi Feb 06 '19 at 13:49
  • @VinayAvasthi since he did not assign any value to it, it will work. you can assign a value to a final variable only once, which is what he did (if, else) – Uri Loya Jan 22 '20 at 09:43
0

The lambda expression needs a final variable. If the initialization code is complicated enough then define a new final variable.

final String fName = name;
CompletableFuture.runAsync(() -> doX(fName));
vavasthi
  • 922
  • 5
  • 14
0

Try to decouple resolver logic from the main flow:

public static void somewhere() {
    // Variable even may be explicitly final
    final String name = resolve(true);
    CompletableFuture.runAsync(() -> doX(name));
}

public String resolve(boolean condition) {
    if (condition)
        return "NameX";

    return "NameY";

    // Or:
    // return condition ? "NameX" : "NameY";
}

The advantage of the approach that you may add more complex conditions and can change this logic later without touching the original flow.

J-Alex
  • 6,881
  • 10
  • 46
  • 64