奇怪的 Java 变量绑定行为

Strange Java variable binding behavior

我有以下class

public class Envirionment {

    private Square[][] grid;

    public Envirionment(int width, int height) {
        this.grid = new Square[height][width];
    }

    public void map(SquareActor actor) {
        for(int y = 0; y < grid.length; y++) {
            for(int x = 0; x < grid[y].length; x++) {
                actor.act(grid[y][x]);
            }
        }

    }
}

为了测试map方法是否正常工作,我开始构建一个测试,测试的目标是传入一个可以作用于方块的函数,看看它是否正常工作正确。

这个测试的主要部分之一是确保它实际上循环遍历所有方块,所以我想我可以传入一个函数,它可以绑定到 xy xy 的值调用回调函数,并在测试中保留一个本地计数器进行比较和对比。

我开始测试是否可以传入一个函数,该函数只会打印出 xy 变量,但我遇到了第一个障碍。

class EnvirionmentTest {

    @Test
    void test() {
        Envirionment env = new Envirionment(10, 10);
        env.map((square) -> System.out.println(String.format("%d, %d", x, y)));
        fail("Not yet implemented");
    }

}

原来编译器开始对我大喊大叫,因为 xy 不能解析为变量,但是我认为它们会绑定到它们将在其中调用的循环范围.

是否可以在 java 中设置这些变量的绑定?还是我完全错误地解决了这个问题?


编辑:

我刚刚在 python 中尝试了类似的东西,它似乎工作正常。

test = lambda : print(str(x) + "," str(y))
for y in range(2):
    for x in range(2):
        test()

输出:

0,0
1,0
0,1
1,1

在 Square class 中,您可以将这些 x 和 y 值定义为局部变量,然后像这样使用 lambda 函数:

  env.map((square) -> System.out.println(String.format("%d, %d", square.x, square.y)));

在您的 python 示例中,您创建了 lambda 表达式,它在 Java 中具有等效项,例如:

BiConsumer<String, String> biFunction = (x, y) -> System.out.println(x + "," + y);

在您的示例中,您会收到编译错误,因为在此表达式中:

env.map((square) -> System.out.println(String.format("%d, %d", x, y)));

编译器不知道 xy 是什么,他是对的。

您的 Environment::map 方法采用 SquareActor 类型的参数。您正在将 lambda 表达式传递给 Environment::map,它将被解析为实施 SquareActor 的匿名 class 的实例,它必须是 FunctionalInterface。在您的情况下,您的 lambda 表达式必须看起来像

env.map((square, x, y) -> System.out.println(String.format("%d, %d", x, y)));

但它不会匹配 SquareActor::act 方法签名。 Java 不支持你认为的闭包。如果您想知道如何在 Java 中实现闭包,请查看 this article.

您的 Environment::map 方法只是循环遍历内部数组并将参数传递给 SquareActor::act。所以你不应该访问 SquareActor::act 内的本地循环计数器,你不觉得吗?如果你想测试你的方法,你只想检查你的 "mock" 实现是否会被触发很多次 :

env.map(square -> System.out.println(String.format("Square " + square)));

应该足够了(如果你覆盖 Square class 的 toString 方法。