Java:在lambda中分配一个变量

时间:2015-11-04 09:50:45

标签: java regex variables lambda java-8

我不能用Java做到这一点:

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

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

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

4 个答案:

答案 0 :(得分:6)

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

非常丑陋的黑客攻击是改变外部对象而不是分配给变量:

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

这是有效的,因为此处sbeffectively final

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

  • 如果您想拥有默认值,请改用optStr.orElseoptStr.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能够在将来的版本中检测并显示此类代码的警告。