奇怪的Java变量绑定行为

时间:2019-06-08 20:23:06

标签: java python binding closures tdd

我有以下课程

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

2 个答案:

答案 0 :(得分:1)

在Square类中,您可以将这些x和y值定义为局部变量,然后使用如下所示的lambda函数:

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

答案 1 :(得分:1)

在您的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的匿名类实例(必须为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内部的本地循环计数器吗?如果您想测试您的方法,则只想检查您的“模拟”实现是否应被触发多次:

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

应该足够了(如果您为toString类重写了Square方法。