我了解为什么编译器不接受以下内容:
class Foo {
public Supplier<String> makeSupplier() {
String str = "hello";
Supplier<String> supp = () -> return str;
// gives the expected compile error because
// str is not effectively final
// (str is a local variable, compile-time error
// as per JLS 15.27.2.)
str = "world";
return supp;
}
}
让我感到困惑的是,编译器接受以下内容,并且单元测试通过了:
class Bar {
private String str = "hello";
public void setStr(String str) {
this.str = str;
}
public Supplier<String> makeSupplier() {
Supplier<String> supp = () -> { return str; };
return supp;
}
@Test
public void Unit_lambdaCapture() {
Supplier<String> supp = makeSupplier();
Assert.assertEquals(supp.get(), "hello");
setStr("foo");
Assert.assertEquals(supp.get(), "foo");
}
}
为什么上述方法有效并且可以正常工作?欢迎使用指向JLS相关部分的指针(15.27.2节仅讨论局部变量)。
我们都同意第一个例子不能用,因为局部变量或参数必须是最终的或有效的最终才能在lambda表达式主体中使用。
但是您的第二个示例不涉及局部变量或参数,而是str
实例字段。Lambda表达式可以使用与实例方法相同的方式访问实例字段:
15.27.2。
λ体
Lambda主体可以是单个表达式或块(第14.2节)。类似于方法主体,lambda主体描述了每次调用都会执行的代码。
实际上,java编译器lambda$0
从您的lambda表达式中创建了一个私有方法,该方法仅访问实例字段str
:
private java.lang.String lambda$0() {
0 aload_0; /* this */
1 getfield 14; /* .str */
4 areturn;
}
另一观点: 您还可以Supplier
使用普通的匿名内部类来实现:
public Supplier<String> makeSupplier() {
return new Supplier<String>() {
public String get() { return str; }
};
}
从内部类访问实例字段非常普遍,而不是Java 8的专业。
我理解为什么编译器不接受以下内容: 令我困惑的是编译器接受以下内容,并且单元测试通过了: 为什么上面的是有效的,工作正常?欢迎提供JLS相关章节的链接(第15.27.2节。只谈局部变量)。
我已经阅读了许多关于堆栈溢出的文章,试图找出为什么下面的代码1不起作用,但代码2起作用。我发现在6版和7版的不同版本中,行为或编译器存在不一致性https://stackoverflow.com/questions/13864464/use-of-uninitialized-final-field-with-without-this-qualifier.这更多地涉及访问默认的最终变量,无论是否有“
问题内容: 在这里只能是最终的。为什么?如何在不保留为私有成员的情况下重新分配方法? 单击该如何返回?我的意思是, 问题答案: 如注释中所述,其中一些在Java 8中变得无关紧要,在Java 8中final可以隐式使用。但是,只能在匿名内部类或lambda表达式中使用有效的最终变量。 这基本上是由于Java管理闭包的方式。 创建匿名内部类的实例时,该类中使用的任何变量都将通过自动生成的构造函数复制
我遇到了下面的Java代码,起初看起来不错,但从未编译过: 下面是IDE :变量USER_ID可能已分配的错误消息。 将值赋值给静态最终变量有问题吗?
我正在学习Spring Core认证,我对这个基于学习材料的问题的答案有一些疑问。 为什么不允许使用@Configuration注释最终类 为了证实这一论断,我的理由如下: 考虑下面的配置类: 乍一看,这种情况可能看起来很奇怪,因为第一个方法(帐户存储库())将JdbcAcCountRepository对象实例化为一个bean,该对象具有id=AcCountRepository,遵循Spring默
以下是JDK11的源代码: 使用访问器而不是直接使用字段有什么意义?既然访问器方法是最终的,为什么不声明:并删除访问器呢?