Java: Assign a variable within lambda

assigning variable inside lambda foreach()
how to use non final variable in lambda
modifying local variable from inside lambda
assign value inside lambda java
variable used in lambda should be final
local variables in lambda expressions java
set external variable in lambda java
java set variable value in lambda

I cannot do this in Java:

Optional<String> optStr = Optional.of("foo");
String result;
optStr.ifPresent(s -> result = s);

The doc says that the variables used in lambdas must be effectively final. Then how to extract and store something from a lambda into a variable nicely?

Actually the real use case is more complex. I want to apply several regular expressions to a string one after another with matcher.replaceAll. I'm doing this in a forEach lambda and wanted to store intermediate results somewhere.

Java: Assign a variable within lambda, forEach(s -> { value.set("blah"); });. Use an array: String[] value = { null }; list.​forEach(s-> { value[0] = "blah"; });. Or with Java 10+: var wrapper  How to declare a variable within lambda expression in Java? Java 8 Object Oriented Programming Programming A lambda expression is a function that expects and accepts input parameters and produces output results.

If the code

Optional<String> optStr = Optional.of("foo");
String result;
optStr.ifPresent(s -> result = s);

was legal, it still was useless, as the variable result is not definitely assigned after the invocation of ifPresent. Java does not allow reading local variables which are only conditionally initialized. So you would need an alternative value for result for the case of an empty Optional, e.g.:

Optional<String> optStr = Optional.of("foo");
String result=null;// or any other default value
optStr.ifPresent(s -> result = s);

But then, if you have defined such a default/fall-back value, you can use the method intended for this purpose:

Optional<String> optStr = Optional.of("foo");
String result=optStr.orElse(null /* or any other default value */);

When you say, you have to initialize more than one variable, it doesn’t change the fact that these variables need to be initialized in either case. Also, there is no benefit in performing the initialization of dependent variables inside a lambda expression passed to the Optional as, after all, the Optional carries only a single value. Everything dependent on that value can get determined after getting that value, independently of the Optional:

Optional<String> optStr = Optional.of("foo");
Type1 variable1;
Type2 variable2;
Type3 variable3;
if(optStr.isPresent()) {
    String s=optStr.get();
    // determine and assign variable1, variable2, variable3 based on s
} else {
    // assign defaults/fall-backs to variable1, variable2, variable3
}

Note that even if your variables are already pre-initialized and you want to mutate them, using if(optional.isPresent()) /* local modifications */ is the simplest way to do it. There’s nothing that works better when you replace this idiom with a lambda expression.

Modifying local variable from inside lambda, If you try to assign a variable inside lambda, which was global or declared outside, you will encounter this error — “Variable used in lambda expression should  Java 8 — Assigning variable inside lambda forEach() If you try to assign a variable inside lambda, which was global or declared outside, you will encounter this

Another way, similar to what Tunaki has written, is to use a single-cell table:

Optional<String> optStr = Optional.of("foo");
String[] temp = new String[1];
optStr.ifPresent(s -> temp[0] = s);
String result = temp[0];

The table object is final, what changes is its content.

Edit: A word of warning though - before using this hacky solution check out the other answers to OP's question, pointing out why it's a bad idea to use this workaround and consider if it's really worth it!

Java 8, In this article, we discuss how to modify variables inside of Lambda There are multiple ways to set up a zip operation in Java, namely:. A variable inside Lambda must be Final or Effective Final. Let's take a sample problem where we would require a variable to be mutated inside a Lambda expression. Romzo works at FedEx.

As per Java Specification, lambda gets the variable values as final from the surrounding context as the lambda is passed to that context at runtime.

The designer of the piece of code which accepts that lambda expression(or Functional Interface) accepts that interface instance\lambda with the faith that its values will not be altered. To strictly make the lambda faithful in this way Java language specification has kept this condition of accessing local context variables as final.

In short, a lambda is NOT supposed to change the state of the context in which it is invoked.

You can use an array to capture values, but still it is not advisable and hopefully java will detect and show warnings for such code in future revisions.

Modifying Variables Inside Lambdas, We can declare a variable as a final string[] array and able to access that array index within a lambda expression. Example. import java.util.*;  Java 8 lambda within a lambda can't modify variable from outer lambda. Suppose I have a List<String> and a List<Transfomer>. I want to apply each transformer to each string in the list.

How to declare a variable within lambda expression in Java?, Tips and best practices on using Java 8 lambdas and functional interfaces. Why Do Local Variables Used in Lambdas Have to Be Final or a compiler treats every variable as final, as long as it is assigned only once. Java 8 — Assigning variable inside lambda forEach() If you try to assign a variable inside lambda, which was global or declared outside, you will encounter this

Best Practices using Java 8 Lambdas, It is illegal to declare a parameter or a local variable in the lambda that has the same name as a local variable. int first = 0; Comparator<String>  Yes, but instance variables can be referenced and assigned in a lambda, which is surprising to me. Only local variables have the final limitation. – Gerard Jul 31 '14 at 9:35. @Gerard Because an instance variable has the scope of the whole class.

3.7 Lambda Expressions and Variable Scope, We would like to know how to enclose local variable in lambda. Answer. import java.util.Arrays; import java.util.List; import java.util.function  But in the case of the lambda, this.value call gives you access to the variable value which is defined in the UseFoo class, but not to the variable value defined inside the lambda's body. 8. Keep Lambda Expressions Short and Self-explanatory

Comments
  • What is your whole use-case? What do you want to do with result?
  • You might want to take a look at orElse / orElseGet
  • Actually the use case is more complex. The lambda expression is larger and I want to assign certain variables inside the lambda
  • For this particular example, there are obvious alternatives that don't involve leaning on the mutation crutch. Which is also almost certainly true of the "more complex" examples you've got in mind (but haven't shared.)
  • @BrianGoetz the real use case is not a secret. See edited question.
  • The use cases are many. For example if you want to increase an outside integer counter in a forEach lambda you can not do that. Or you just want to store some intermediate results from a cyclic calculation. You have to enclose them in dummy objects.
  • @George Because "increase an outside integer counter in a forEach" sounds a lot like filtering and then counting, which would be a functional way of doing it. Having said that, you could also create your own MutableInteger and increment that object instead. You can't assign but you can mutate.
  • I gave the Optional only for simple illustration. In fact the lambda is arbitrary. Could be a forEach or some custom implementation.
  • @George: the point doesn’t change. You can’t mutate a local variable using lambda expressions. The correct way to do it will depend on each use case, but we can only answer the question you are actually asking, not the one in your mind.
  • I have updated the question with the actual use case.
  • Well, nothing really important has changed. In your original question, you wanted to replace an if statement by lambda expression, now you’re saying that you want to replace a for loop with a lambda expression. The answer still holds. Converting imperative code to use lambda expressions is not an improvement in any way.
  • very useless answer as it appeared on my search for "assigning value of a loca variable inside lambda in java".
  • I totally agree with Tunaki, and the fact that using this workaround is a bad idea, I just pointed out that you can 'hack' it other way.
  • You're absolutely right - I'll edit it pointing to Tunaki's warnings.