Java:在lambda中分配一个变量

我不能用Java做到这一点:

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

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

实际上,真实的用例更复杂。
我想用matcher.replaceAll一个接一个地将几个正则表达式应用于一个字符串。 我在forEach lambda中这样做,并想在某处存储中间结果。

如果是代码

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

是合法的,它仍然没用,因为在调用ifPresent之后没有明确赋值变量result 。 Java不允许读取仅有条件初始化的局部变量。 因此,对于空的Optional ,您需要一个替代值的result ,例如:

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

但是,如果您已经定义了这样的默认/回退值,则可以使用用于此目的的方法:

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

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

 Optional 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表达式替换这个习语时,没有什么比这更好的了。

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

一个非常难看的黑客将改变外部对象而不是分配给变量:

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

这是有效的,因为sb在这里是有效的

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

  • 如果要使用默认值,请改用optStr.orElseoptStr.orElseGet
  • 如果要仅在结果存在时映射结果,请使用optStr.map

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

与Tunaki编写的类似,另一种方法是使用单细胞表:

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

表对象是最终的,其内容有哪些变化。

编辑:虽然有一个警告 – 在使用这个hacky解决方案之前,请查看OP问题的其他答案,指出为什么使用这个解决方法并考虑它是否真的值得它是一个坏主意!

根据Java规范,lambda从周围的上下文中获取变量值作为final,因为lambda在运行时传递给该上下文。

接受该lambda表达式(或function接口)的代码片段的设计者接受该接口实例\ lambda,并确信其值不会被更改。 为了严格按照这种方式使lambda忠实,Java语言规范保持了访问本地上下文变量的最终条件。

简而言之,lambda不应该改变调用它的上下文的状态。

您可以使用数组来捕获值,但仍然不建议,并且希望java将在将来的修订中检测并显示此类代码的警告。