Java:在 lambda 中分配一个变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33518589/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java: Assign a variable within lambda
提问by George
I cannot do this in Java:
我不能在 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?
该文档说 lambda 中使用的变量必须是有效的最终变量。那么如何很好地从 lambda 中提取和存储一些东西到一个变量中呢?
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.
实际上,真正的用例要复杂得多。
我想将几个正则表达式一个接一个地应用于一个字符串matcher.replaceAll
。我在 forEach lambda 中执行此操作并希望将中间结果存储在某处。
回答by Tunaki
The answer is simple: you can't (directly) do that.
答案很简单:你不能(直接)这样做。
A very uglyhack would be to mutate an external object instead of assigning to a variable:
一个非常丑陋的hack 是改变外部对象而不是分配给变量:
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 finalhere
But I want to emphasize the point that this is probably not what you really want to do.
但我想强调一点,这可能不是您真正想要做的。
- If you want to have a default value, use
optStr.orElse
oroptStr.orElseGet
instead. - If you want to map the result only if it is present, use
optStr.map
- 如果您想拥有默认值,请使用
optStr.orElse
或optStr.orElseGet
代替。 - 如果您只想在结果存在时映射结果,请使用
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).
由于您没有提供整个用例,这些只是猜测,但关键是我真的不推荐上面的代码片段:它违背了函数式编程的概念(通过改变对象)。
回答by ttarczynski
Another way, similar to what Tunaki has written, is to use a single-cell table:
另一种方法,类似于 Tunaki 所写的,是使用单单元格表:
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.
table 对象是最终的,改变的是它的内容。
Edit: A word of warning though - before using this hacky solutioncheck 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!
编辑:虽然有一点警告 - 在使用这个hacky 解决方案之前,请查看 OP 问题的其他答案,指出为什么使用这种解决方法是个坏主意,并考虑它是否真的值得!
回答by Holger
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 assignedafter 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.:
是合法的,但它仍然是无用的,因为变量result
不明确赋值的调用之后ifPresent
。Java 不允许读取仅条件初始化的局部变量。因此,result
对于空的情况,您需要一个替代值Optional
,例如:
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 aftergetting that value, independently of the Optional
:
当您说必须初始化多个变量时,这并没有改变在任何一种情况下都需要初始化这些变量的事实。此外,在传递给Optional
as的 lambda 表达式中执行因变量的初始化也没有任何好处,毕竟, theOptional
只携带一个值。在获得该值后,可以确定依赖于该值的一切,独立于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.
请注意,即使您的变量已经预先初始化并且您想要改变它们,使用if(optional.isPresent()) /* local modifications */
也是最简单的方法。当你用 lambda 表达式替换这个习语时,没有什么比这更好的了。
回答by Dhruv Rai Puri
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.
根据 Java 规范,当 lambda 在运行时传递给该上下文时,lambda 从周围的上下文中获取作为 final 的变量值。
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.
接受 lambda 表达式(或函数式接口)的代码的设计者接受该接口 instance\lambda 并相信其值不会改变。为了严格按照这种方式使 lambda 忠实,Java 语言规范将访问局部上下文变量的这种条件保持为 final。
In short, a lambda is NOT supposed to change the state of the context in which it is invoked.
简而言之,一个 lambda 不应该改变它被调用的上下文的状态。
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.
您可以使用数组来捕获值,但仍然不可取,希望 java 在未来的修订版中检测并显示此类代码的警告。