我对函数式语言和闭包很满意,并对以下错误感到惊讶:"不能引用封闭范围中定义的非最终局部变量邀请".
这是我的代码:
Session dbSession = HibernateUtil.getSessionFactory().openSession();
Transaction dbTransaction = dbSession.beginTransaction();
Criteria criteria = dbSession.createCriteria(Invite.class).add(Restrictions.eq("uuid", path).ignoreCase());
Invite invite = (Invite) criteria.uniqueResult();
if (invite.isExpired()) {
// Notify user the invite has expired.
} else {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// ERROR: `invite` is not guaranteed to exist when this code runs
invite.setExpired(true);
}
}, MAX_TIME);
}
Run Code Online (Sandbox Code Playgroud)
据我了解,invite在TimeTask实例中引用是一个错误,因为不保证该变量存在.所以我的问题是,表达我想要的Java的方式是什么,即加载一个邀请,然后设置一个计时器,在一段时间后使邀请过期.
有两种方法可以解决此问题:
声明invite为final这样它就可以被匿名内部类访问。
final Invite invite = (Invite) criteria.uniqueResult();
...
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
invite.setExpired(true);
}
}, MAX_TIME);
Run Code Online (Sandbox Code Playgroud)将匿名内部类从等式中剔除:
public class InviteTimeoutTask extends TimerTask {
private final Invite invite;
public InviteTimeoutTask(Invite invite) {
this.invite = invite;
}
@Override
public void run() {
invite.setExpired(true);
}
}
Run Code Online (Sandbox Code Playgroud)
然后像这样使用它:
final Invite invite = (Invite) criteria.uniqueResult();
...
Timer timer = new Timer();
timer.schedule(new InviteTimeoutTask(invite), MAX_TIME);
Run Code Online (Sandbox Code Playgroud)您只能引用final匿名内部类中的变量的原因很简单,您正在处理局部变量。如果你在一个字段上尝试同样的事情,你不会遇到任何问题。但局部变量的作用域仅限于它所属的方法。当调用 中的回调方法时,TimerTask创建 的方法早已TimerTask结束,所有局部变量都消失了。但是,如果您将变量声明为final编译器可以在匿名类中安全地使用它。