2

I have a lambda function that is sent to another function, i want to change a variable that is declared outside of the lambda scope, in the lambda.

    WebElement  textArea ;
    BrowserToucher.clickOnWebElement(() -> {
        WebElement convPopupOrCard = findElementBy(driver, 
            conversationCardOrPopup);
        return textArea = findSubElementBy(driver, convPopupOrCard, 
            CardAndPopupTextArea);  
        }, driver);
    BrowserToucher.sendKeys(textArea, driver, text);

I need to change the 'textArea' var in the labmda, so i can use its value in the last line.

The only solution i've found is to make 'textArea' an array in size of 1. But I don't really understand why it works. Would love if anyone can explain that to me please. Thank you!!

Serjio
  • 23
  • 5

3 Answers3

2

The only solution i've found is to make 'textArea' an array in size of 1 But I don't really understand why it works.

It works because the captured array itself is either final or effectively final (any variable whose value does not change).

As long as the captured variable is final or effectively final changing the contents of the array is completely fine & permissible.

Of course, code like this is not threadsafe. So, ideally, you should think twice before using this trick.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
1

If I understand your problem correctly, the solution is not that hard if you remember that lambdas are just function but without the names, so you can pass any argument in the brackets there as you do with 'regular' java methods.

The only solution i've found is to make 'textArea' an array in size of 1. But I don't really understand why it works.

This is already very well described in one of stack overflow topics regarding java reference. Please get familiar with it, and you will understand it for good, and maby came up with another solution for your problem :)

Is Java "pass-by-reference" or "pass-by-value"?

  • Yep maybe I was not that precise. I was thinking about "cutmancometh" answer to this topic. He describes how the arrays are working for java. My point was, that in this case using an array, you work on this object "reference" so they say, so we are not really messing with object itself (witch give Us as you said final or effectively final) and it will be the reason why the solution works. I did not come into deep details, as you already have below. By the way a very good "under the hood" explanation for that. Thanks for that! I have learned something to :) – Przemysław Gęsieniec Jun 13 '18 at 11:02
1

Variables inside a lambda, or any anonymous inner class, need to be final or effectively final.

This is because those variables are copied to the lambda scope. If they were referenced instead of copied, a problem would arise when the variable goes out of scope of its declaration zone, while the lambda scope is still executing (think threads).

By defining an array, you are working around that problem: you're forcibly referencing the value, with an effectively final array (you initialize the array once, and never change it).

Final and effectively final variables can safely be copied, knowing that their value is not going to change.

When array goes out of scope, no problem, the GC still holds a pointer to you value from inside the lambda scope and it's not going to be garbage-collected until both lambda and the declaring zone are out of scope.

You could do the same with list, or any other collection. It'd also work with a wrapper class.

Ahmad Shahwan
  • 1,662
  • 18
  • 29