如何将TimerTask与lambdas一起使用?

时间:2014-03-13 12:18:06

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

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

这里可以看到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时有没有办法使用lambdas?

我想要的是以下内容:

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

而不是一些丑陋的匿名内部类,有没有办法让它变得更好?

5 个答案:

答案 0 :(得分:11)

首先注意到Timer实际上是一个过时的API,但是尽管如此,你可以在它周围写一个小包装器,它会调整schedule方法来接受Runnable,在内部,你将Runnable变成TimerTask。那么你将拥有接受lambda的schedule方法。

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;
  }
}

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

虽然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冲突。

答案 3 :(得分:0)

我知道这是一篇过时的文章,但为完整起见,我想包括wrapper solution发表的Flown

private static TimerTask wrap(Runnable r) {
  return new TimerTask() {

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

那么您的通话可以变成:

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

答案 4 :(得分:-1)

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

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