【问题标题】:How to use TimerTask with lambdas?如何将 TimerTask 与 lambda 一起使用?
【发布时间】:2014-03-13 12:18:05
【问题描述】:

如您所知,您可以在 Java 8 中使用 lambda,例如替换匿名方法。

这里可以看到 Java 7 与 Java 8 的示例:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        checkDirectory();
    }
};

在Java 8中可以表示为以下两种方式:

Runnable runnable = () -> checkDirectory();

Runnable runnable = this::checkDirectory;

这是因为Runnable 是一个函数式接口,只有一个(抽象的)公共非默认方法。

但是...对于TimerTask,我们有以下内容:

TimerTask timerTask = new TimerTask() {
    @Override
    public void run() {
        checkDirectory();
    }
};

看起来很眼熟,对吧?
但是使用 lambda 表达式不起作用,因为 TimerTask 是一个抽象类,即使它只有一个抽象的公共非默认方法,它也不是接口,因此也没有功能接口。
它也没有被重构为具有默认实现的接口,因为它带有状态,因此无法做到。

所以我的问题:有没有办法在构造TimerTask 时使用 lambda?

我想要的是以下内容:

Timer timer = new Timer();
timer.schedule(this::checkDirectory, 0, 1 * 1000);

除了一些丑陋的匿名内部类之外,有什么方法可以让它变得更好?

【问题讨论】:

  • 既然您使用现代功能,为什么不一直使用ScheduledExecutorService 而不是TimerTask? ;)
  • @fge 好吧,我不知道它存在,直到现在......现在我想,Java 没有他们的 API 提到有一个更新的类似功能可用功能尚未弃用
  • 对于Timer,Josh Bloch 的 Effective Java 2nd Edition 建议这样做。不过,这不是 JDK API 的官方立场。
  • 呃,不......这无疑是他们的文档中的一大缺陷。同样,他们在File 文档中也没有提及Files

标签: java lambda abstract-class timertask java-8


【解决方案1】:

首先注意到Timer 实际上是一个过时的API,但尽管如此,您的问题还是很有趣,您可以围绕它编写一个小包装器,它会调整schedule 方法以接受Runnable,并在您的内部' d 把 Runnable 变成 TimerTask。然后你就会有你的schedule 方法,它可以接受一个 lambda。

public class MyTimer {
  private final Timer t = new Timer();

  public TimerTask schedule(final Runnable r, long delay) {
     final TimerTask task = new TimerTask() { public void run() { r.run(); }};
     t.schedule(task, delay);
     return task;
  }
}

【讨论】:

  • 技术上你的答案是正确的,但是我个人会选择ScheduledExecutorService而不是TimerTask
  • 那么当前的 API 是什么?
【解决方案2】:

要完成 Marko Topolnik 关于 Timer 的回答,您只需使用 lambda 调用 schedule 方法。

schedule(() -> {
    System.out.println("Task #1 is running");
}, 500);

【讨论】:

  • Runnable 是一个接口,你可以用 lambda 实现它。因此,您可以使用 lambda 调用 schedule 方法。这是一个工作要点gist.github.com/fsamin/ec5aa79bc23965eca277
  • 被误解的答案;你当然是完全正确的。
【解决方案3】:

虽然 Marko 的回答完全正确,但我更喜欢我的实现:

public class FunctionalTimerTask extends TimerTask {

    Runnable task;

    public FunctionalTimerTask(Runnable task) {
        this.task = task;
    }

    @Override
    public void run() {
        task.run();
    }
}

 public static class Task {
    public static TimerTask set(Runnable run) {
        return new FunctionalTimerTask(() -> System.err.println("task"));
    }
}

 Timer timer = new Timer(false);
 timer.schedule(Task.set(() -> doStuff()), TimeUnit.SECONDS.toMillis(1));

这使您可以更好地控制计时器,并且您有一个静态实用程序类。理想情况下,给它起一个不会与其他常见线程类冲突的名称,而不是 Task、Job、Timer。

【讨论】:

    【解决方案4】:

    我知道这是一篇旧帖子,但为了完整起见,我想包括Flown 发布的wrapper solution

    private static TimerTask wrap(Runnable r) {
      return new TimerTask() {
    
        @Override
        public void run() {
          r.run();
        }
      };
    }
    

    那么你的电话可以变成:

    timer.schedule(wrap(this::checkDirectory), delay);
    

    【讨论】:

      【解决方案5】:

      如果需要,您还可以使用 Swing API 中的 lambda 轻松创建 Timer(但不能使用 TimerTask):

      new javax.swing.Timer(1000, (ae) -> this::checkDirectory).start();

      【讨论】:

        猜你喜欢
        • 2015-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-05
        • 2021-06-22
        • 2019-10-16
        • 2021-05-02
        相关资源
        最近更新 更多