奇怪的 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
方法是否正常工作,我开始构建一个测试,测试的目标是传入一个可以作用于方块的函数,看看它是否正常工作正确。
这个测试的主要部分之一是确保它实际上循环遍历所有方块,所以我想我可以传入一个函数,它可以绑定到 x
和 y
x
和 y
的值调用回调函数,并在测试中保留一个本地计数器进行比较和对比。
我开始测试是否可以传入一个函数,该函数只会打印出 x
和 y
变量,但我遇到了第一个障碍。
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");
}
}
原来编译器开始对我大喊大叫,因为 x
和 y
不能解析为变量,但是我认为它们会绑定到它们将在其中调用的循环范围.
是否可以在 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)));
编译器不知道 x
和 y
是什么,他是对的。
您的 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
方法。
我有以下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
方法是否正常工作,我开始构建一个测试,测试的目标是传入一个可以作用于方块的函数,看看它是否正常工作正确。
这个测试的主要部分之一是确保它实际上循环遍历所有方块,所以我想我可以传入一个函数,它可以绑定到 x
和 y
x
和 y
的值调用回调函数,并在测试中保留一个本地计数器进行比较和对比。
我开始测试是否可以传入一个函数,该函数只会打印出 x
和 y
变量,但我遇到了第一个障碍。
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");
}
}
原来编译器开始对我大喊大叫,因为 x
和 y
不能解析为变量,但是我认为它们会绑定到它们将在其中调用的循环范围.
是否可以在 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)));
编译器不知道 x
和 y
是什么,他是对的。
您的 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
方法。