Java8中非final变量在编译时出现“Effectively Final”错误

8

我正在尝试在java8 forEach循环中更改非final的布尔变量为true。但是我得到了以下错误:要求在封闭范围内定义的局部变量必须是final或有效final。

如何解决这个错误?

代码:

boolean required = false; 

这是我在函数中创建的变量。

现在当我试图更改它时:

   map.forEach((key, value) -> {
        System.out.println("Key : " + key + " Value : " + value);
        required = true;
    });

我遇到了这个错误:本地变量必须是 final 或 effectively final,定义在封闭作用域中。

为什么会出现这个错误,如何解决?

1个回答

8

您不能从lambda表达式的主体更改局部变量。有几种方法可以解决这个问题:

  • In this particular case you can just set boolean required = !map.isEmpty(); without any lambda expression. If you want to set it based on some condition, you can use the Stream API:

    boolean required = map.entrySet().stream().anyMatch(entry -> ...);
    

    This solution is the most preferred.

  • Convert the required variable to the field of the enclosing class.

  • The most dirty way: declare a one-element array: boolean[] required = {false}; and set this element instead: required[0] = true;

1
像这样最不规范的方式:声明一个只有一个元素的数组:boolean[] required = {false};并设置该元素:required [0] = true;我确实想这么做,但像你说的那样看起来很不规范。在 lambda 表达式中是否有其他更好的方法可以更改局部变量呢? @tagirValeev - Siddharth Sachdeva
3
@Siddharth,实际上没有办法改变局部变量。在boolean[] required的情况下,您不会更改局部变量,而是更改堆对象。 - Tagir Valeev
1
为了增加我的知识,您能否解释一下“更改头对象但不更改本地变量”实际上是什么意思。@tagirValeev - Siddharth Sachdeva
5
比使用一个只有一个元素的数组更好看一点的方法是使用 AtomicBoolean,可以通过 set(boolean) 方法改变其值。 - dkatzel
是的,即使将布尔变量封装在类中并使用它也可以工作。@dkatzel - Siddharth Sachdeva
@Siddharth,一个普通的Boolean对象是不起作用的,因为你不能改变该对象的值,也不能创建一个new Boolean(),因为引用必须是(有效地)最终的。 - dkatzel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接