groovy是否尊重在闭包或匿名类之外定义的最终变量?

时间:2013-07-04 09:37:25

标签: groovy scope closures final

今天我在将一些java代码移植到groovy时发现了groovy的一些重要行为。

我们在java中一直做的事情:在循环中构建匿名类(例如用于动作)并引用在此类之外声明的最终变量。

如果你让我们在groovy中运行这个代码,你会惊讶地得到1,2,3,4,5,6,7,8,9,但你会得到9,9,9,9,9,9 ,9,9,9。这意味着groovy不会将相应的最终变量i绑定到每个匿名类,而只是使用exectution上的最后一个设置值。

我在groovy文档中找不到任何这种行为的原因。顺便说一句,如果我使用groovy闭包而不是匿名类,我会得到相同的行为。

public static void main(String[] args) {
    int[] list = new int[10];
    for (int i = 0; i < 10; i++) {
        list[i] = i;
    }
    Runnable[] runnables = new Runnable[10];
    for (final int i : list) {
        runnables[i] = new Runnable() {
            @Override
            public void run() {
                System.out.println(i);
            }
        };
    }

    for (int i = 0; i < 10; i++) {
        runnables[i].run();
    }
}

2 个答案:

答案 0 :(得分:3)

奇怪......我会调查一下这是否已知行为

同时,您可以通过在循环内声明生成runnables的另一个变量来解决它,然后在Runnable中使用它:

for (int i : list) {
    int k = i
    runnables[i] = new Runnable() {
        @Override
        public void run() {
            System.out.println(k);
        }
    }
}

或者使用collect

生成Runnable数组
Runnable[] runnables = list.collect { i -> 
    new Runnable() {
        @Override
        public void run() {
            System.out.println( i );
        }
    }
}

修改

我已经问过了,在类属性之外,Groovy目前忽略了final。这是可以在未来添加的东西

答案 1 :(得分:0)

我认为问题出在for循环上。简化代码:

def runnables = []
for (int i: 0..9) {
    runnables << {
        println i
    }
}
runnables*.call() // prints 9, 9, 9, 9, 9, 9, 9, 9, 9, 9

有趣的是,传统的for循环输出所有10个:

def runnables = []
for (int i = 0; i < 10; ++i) {
    runnables << {
        println i
    }
}
runnables*.call() // prints 10, 10, 10, 10, 10, 10, 10, 10, 10, 10

使用范围代替for循环将按预期工作:

def runnables = []
(0..9).each { i ->
    runnables << {
        println i
    }
}
runnables*.call() // prints 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

所以是的,闭包(或匿名的Runnable)在被调用时,会从已经执行的i循环的范围内查找for的引用,此时{的值{ {1}}处于完全递增的值。我不确定这是否是故意的。