我不能用Java做到这一点:
Optional<String> optStr = Optional.of("foo");
String result;
optStr.ifPresent(s -> result = s);
文档说lambda中使用的变量必须是有效的。 那么如何很好地从lambda中提取和存储一些东西呢?
实际上,真实用例更复杂
我想用matcher.replaceAll
一个接一个地将几个正则表达式应用于字符串。我在forEach lambda中这样做,并希望在某处存储中间结果。
答案 0 :(得分:6)
答案很简单:你不能(直接)这样做。
非常丑陋的黑客攻击是改变外部对象而不是分配给变量:
Optional<String> optStr = Optional.of("foo");
StringBuilder sb = new StringBuilder();
optStr.ifPresent(s -> sb.append(s));
String result = sb.toString();
这是有效的,因为此处sb
为effectively final
但我想强调一点,这可能不是你真正想做的事。
optStr.orElse
或optStr.orElseGet
。optStr.map
由于你没有提供你的整个用例,这些只是猜测,但关键是我真的不推荐上面的代码片段:它违背了函数式编程的概念(通过改变一个对象)。
答案 1 :(得分:3)
与Tunaki所写的类似,另一种方法是使用单格表:
Optional<String> optStr = Optional.of("foo");
String[] temp = new String[1];
optStr.ifPresent(s -> temp[0] = s);
String result = temp[0];
表对象是最终的,其内容会发生什么变化。
编辑:虽然在使用此 hacky解决方案之前发出警告,但请查看OP问题的其他答案,并指出为什么使用此解决方案不明智并考虑它是否真的值得!
答案 2 :(得分:3)
如果代码
Optional<String> optStr = Optional.of("foo");
String result;
optStr.ifPresent(s -> result = s);
是合法的,但仍然没用,因为在调用result
之后变量ifPresent
不是definitely assigned。 Java不允许读取仅有条件地初始化的局部变量。因此,对于空result
的情况,您需要Optional
的替代值,例如:
Optional<String> optStr = Optional.of("foo");
String result=null;// or any other default value
optStr.ifPresent(s -> result = s);
但是,如果您已经定义了这样的默认/后退值,则可以使用用于此目的的方法:
Optional<String> optStr = Optional.of("foo");
String result=optStr.orElse(null /* or any other default value */);
当你说,你必须初始化多个变量时,它不会改变这两个变量在这两种情况下都需要初始化的事实。此外,在传递给Optional
的lambda表达式中执行因变量的初始化没有任何好处,因为,Optional
只携带一个值。在获取该值后,依赖于该值的所有内容都可以确定,与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
}
请注意,即使您的变量已经预先初始化并且您想要改变它们,使用if(optional.isPresent()) /* local modifications */
也是最简单的方法。当你用lambda表达式替换这个习语时,没有什么比这更好的了。
答案 3 :(得分:1)
根据Java规范,lambda从周围的上下文中获取变量值为final,因为lambda在运行时传递给该上下文。
接受lambda表达式(或Functional Interface)的代码片段的设计者接受该接口实例\ lambda,并确信其值不会被更改。为了严格按照这种方式使lambda忠实,Java语言规范保持了访问本地上下文变量的最终条件。
简而言之,lambda不应该改变调用它的上下文的状态。
您可以使用数组来捕获值,但仍然不建议这样做,希望java能够在将来的版本中检测并显示此类代码的警告。