什么是Java处理闭包的方式?

gwg*_*gwg 5 java

我对函数式语言和闭包很满意,并对以下错误感到惊讶:"不能引用封闭范围中定义的非最终局部变量邀请".

这是我的代码:

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)

据我了解,inviteTimeTask实例中引用是一个错误,因为不保证该变量存在.所以我的问题是,表达我想要的Java的方式是什么,即加载一个邀请,然后设置一个计时器,在一段时间后使邀请过期.

Xav*_*ler 2

有两种方法可以解决此问题:

  1. 声明invitefinal这样它就可以被匿名内部类访问。

    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)
  2. 将匿名内部类从等式中剔除:

    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编译器可以在匿名类中安全地使用它。