Java:在 lambda 中分配一个变量

2022-09-02 21:55:54

我无法在Java中执行此操作:

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

该文档说,lambda中使用的变量必须有效地是最终的。那么如何很好地从lambda中提取和存储一些东西到变量中呢?

实际上,真正的用例更复杂。
我想用.一个接一个地对一个字符串应用几个正则表达式。我正在 forEach lambda 中执行此操作,并希望将中间结果存储在某个地方。matcher.replaceAll


答案 1

答案很简单:你不能(直接)这样做。

个非常丑陋的技巧是改变一个外部对象,而不是分配给一个变量:

Optional<String> optStr = Optional.of("foo");
StringBuilder sb = new StringBuilder();
optStr.ifPresent(s -> sb.append(s));
String result = sb.toString();

这有效,因为在这里实际上是最终的sb

但我想强调一点,这可能不是你真正想做的。

  • 如果要具有默认值,请使用 或 代替。optStr.orElseoptStr.orElseGet
  • 如果只想在结果存在时才映射结果,请使用optStr.map

由于您没有提供整个用例,这些只是猜测,但关键的一点是我真的不推荐上面的代码片段:它违背了函数式编程的概念(通过改变对象)。


答案 2

如果代码

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

是合法的,但它仍然是无用的,因为在调用后变量没有明确分配。Java 不允许读取仅进行条件初始化的局部变量。因此,对于空的情况,您需要一个替代值,例如:resultifPresentresultOptional

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 */);

当你说,你必须初始化多个变量时,它不会改变这些变量在任何一种情况下都需要初始化的事实。此外,在传递给 as 的 lambda 表达式中执行因变量的初始化也没有好处,毕竟,只携带一个值。依赖于该值的所有内容都可以在获得该值确定,而与:OptionalOptionalOptional

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
}

请注意,即使您的变量已经预先初始化并且您想要改变它们,使用是最简单的方法。当您将此成语替换为 lambda 表达式时,没有什么比这更好的了。if(optional.isPresent()) /* local modifications */