I cannot do this in Java:
Optional optStr = Optional.of(\"foo\");
String result;
optStr.ifPresent(s -> result = s);
The doc sa
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.
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!
The answer is simple: you can't (directly) do that.
A very ugly hack would be to mutate an external object instead of assigning to a variable:
Optional<String> optStr = Optional.of("foo");
StringBuilder sb = new StringBuilder();
optStr.ifPresent(s -> sb.append(s));
String result = sb.toString();
This works because sb
is effectively final here
But I want to emphasize the point that this is probably not what you really want to do.
optStr.orElse
or optStr.orElseGet
instead.optStr.map
Since you did not provide your whole use-case, these are just guesses but the key point is that I really do not recommend the above snippet of code: it goes against the concept of functional programming (by mutating an object).
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.