lambda表达式中使用的变量应该是final或者有效的final
当我尝试使用calTz它时显示此错误.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if (calTz == null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
});
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
Vin*_*igh 67
虽然其他答案证明了这一要求,但它们并未解释为何存在这一要求.
JLS在§15.27.2中提到了为什么:
对有效最终变量的限制禁止访问动态变化的局部变量,其捕获可能会引入并发问题.
为了降低错误风险,他们决定确保捕获的变量永远不会发生变异.
Fra*_*lis 57
甲final变量意味着它可以被实例化一次.在Java中,您不能在lambda和匿名内部类中使用非final变量.
您可以使用旧的for-each循环重构代码:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
try {
for(Component component : cal.getComponents().getComponents("VTIMEZONE")) {
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(calTz==null) {
calTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());
}
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
即使我没有理解这些代码的某些部分:
v.getTimeZoneId();不用使用它的返回值就调用acalTz = TimeZone.getTimeZone(v.getTimeZoneId().getValue());如果您没有修改最初传递的作业,则不要calTz在此方法中使用它null,为什么不设置void为返回类型?希望这些技巧也可以帮助您改进.
小智 46
从lambda中,你无法获得任何非最终的参考.您需要从lamda外部声明一个最终包装器来保存您的变量.
我添加了最终的'reference'对象作为这个包装器.
private TimeZone extractCalendarTimeZoneComponent(Calendar cal,TimeZone calTz) {
final AtomicReference<TimeZone> reference = new AtomicReference<>();
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component->{
VTimeZone v = (VTimeZone) component;
v.getTimeZoneId();
if(reference.get()==null) {
reference.set(TimeZone.getTimeZone(v.getTimeZoneId().getValue()));
}
});
} catch (Exception e) {
//log.warn("Unable to determine ical timezone", e);
}
return reference.get();
}
Run Code Online (Sandbox Code Playgroud)
Din*_*ora 37
Java 8有一个名为"Effectively final"变量的新概念.这意味着一个非最终的局部变量,其值在初始化后永远不会改变,称为"有效最终".
引入这个概念是因为在Java 8之前,我们不能在一个非最终的局部变量中使用final.如果您想访问本地变量final,则必须使其成为最终变量.
什么final时候推出,这个限制得到了缓解.因此,final如果局部变量一旦被初始化就不会被改变,因此需要制作局部变量本身只是一个匿名类.
Java 8意识到final每次开发人员使用final和引入这个概念时都会声明局部变量,并且无需创建局部变量final.因此,如果您看到规则final仍未更改,则只需final每次使用时都不必编写关键字final.
我在这里找到了一个很好的解释
在您的示例中,您可以forEach使用简单for循环替换with lamdba 并自由修改任何变量.或者,可能会重构您的代码,以便您不需要修改任何变量.但是,我将解释完整性错误的含义以及如何解决它.
Java 8语言规范,§15.27.2:
使用但未在lambda表达式中声明的任何局部变量,形式参数或异常参数必须声明为final或者是有效的final(§4.12.4),否则在尝试使用时会发生编译时错误.
基本上你不能calTz从lambda(或本地/匿名类)中修改局部变量(在这种情况下).要在Java中实现这一点,您必须使用可变对象并从lambda中修改它(通过最终变量).这里可变对象的一个例子是一个元素的数组:
private TimeZone extractCalendarTimeZoneComponent(Calendar cal, TimeZone calTz) {
TimeZone[] result = { null };
try {
cal.getComponents().getComponents("VTIMEZONE").forEach(component -> {
...
result[0] = ...;
...
}
} catch (Exception e) {
log.warn("Unable to determine ical timezone", e);
}
return result[0];
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
143493 次 |
| 最近记录: |