考虑以下几乎可编译的Java 8代码:
public static void main(String[] args) {
LinkedList<User> users = null;
users.add(new User(1, "User1"));
users.add(new User(2, "User2"));
users.add(new User(3, "User3"));
User user = users.stream().filter((user) -> user.getId() == 1).findAny().get();
}
static class User {
int id;
String username;
public User() {
}
public User(int id, String username) {
this.id = id;
this.username = username;
}
public void setUsername(String username) {
this.username = username;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public int getId() {
return id;
}
}
您会注意到User user = users.stream().filter((user) -> user.getId() == 1).findAny().get();
抛出一个编译器错误:
变量用户已在方法main(String[])中定义
我的问题是:为什么Lambda表达式考虑与已经定义的Lambda表达式在同一行上初始化的变量?我理解Lambda自己寻找(并使用)局部变量,因此不能将在Lambda中使用的变量命名为外部变量。但是,为什么被定义的变量被认为已经定义了呢?
发布于 2014-03-31 15:40:26
让我们来看看关于名称及其作用域的Java语言规范
方法(§8.4.1)、构造函数(§8.8.1)或lambda表达式(§15.27)的形式参数的范围是方法、构造函数或lambda表达式的整个主体。 块中局部变量声明的作用域(§14.4)是声明显示为的块的其余部分,从它自己的初始化器开始,并在局部变量声明语句中包含右边的任何其他声明器。
然后,以遮蔽和遮挡为主题
局部变量(§14.4)、形式参数(§8.4.1、§15.27.1)、异常参数(§14.20)和本地类(§14.3)只能使用简单的名称,而不是限定的名称(§6.2)。 某些声明在局部变量、形式参数、异常参数或本地类声明的范围内是不允许的,因为仅使用简单的名称就不可能区分声明的实体。 如果使用局部变量v的名称来声明v范围内的新变量,则为编译时错误,除非新变量是在声明在v.范围内的类中声明的。
所以,在
User user = users.stream().filter((user) -> user.getId() == 1).findAny().get();
变量user
的作用域是该块中它之后的所有内容。现在,您正在尝试使用该变量的名称在作用域中声明一个新变量,但不使用
声明在v.范围内的类中的
因此会出现编译时错误。(它是在lambda表达式中声明的,而不是在类中声明的)
发布于 2014-03-31 14:00:51
看看代码
User user = users.stream().filter((user) -> user.getId() == 1).findAny().get();
变量名为user
,lambda中的变量也是user
。
试着把它改变成这样
User user = users.stream().filter((otherUser) -> otherUser.getId() == 1).findAny().get();
发布于 2017-11-09 07:12:04
注意,这个限制将在以后的版本中被删除。来自九月-302号的报价
Lambda参数不允许在封闭作用域中隐藏变量。(换句话说,lambda的行为类似于for语句-参见JLS),这通常会导致问题,如下(非常常见)所示:
Map<String, Integer> msi = ...
...
String key = computeSomeKey();
msi.computeIfAbsent(key, key -> key.length()) //error
在这里,在computeIfAbsent调用中将名称键重用为lambda参数的尝试失败了,因为在封闭上下文中已经定义了同名变量。 最好取消这个限制,允许lambda参数(和用lambda声明的局部变量)隐藏在包围作用域中定义的变量。(反对的一个可能的论点是可读性:如果允许lambda参数阴影,那么在上面的示例中,标识符'key‘意味着在使用它的两个地方有两个不同的东西,并且似乎没有语法障碍来分隔这两个用法。)
https://stackoverflow.com/questions/22773003
复制