27

I want to perform a delayed operation on a map, so I am using Timer, to which I am passing a TimerTask and a delay in milliseconds:

timer.schedule(new TimerTask() {
    public void run() {
        tournaments.remove(id);
    }
}, delay);

This is some sort of primitive cache-like functionality where I set an expiration time on a new resource that was just created.

I thought I could do that using lambdas, just like follows:

times.schedule(() -> tournaments.remove(id), delay);

But the compiler says this cannot be done. Why? What am I doing wrong? Could I use lambdas to achieve more concise code or it's simply not possible here and I should stick to an anonymous class?

dabadaba
  • 9,064
  • 21
  • 85
  • 155
  • 3
    What does the compiler tell you? Also, you're missing the second `delay` parameter in your example. – Zircon Jun 22 '16 at 14:16
  • 1
    It says *"cannot resolve method schedule(, long)"* – dabadaba Jun 22 '16 at 14:21
  • 5
    You should use `ScheduledExecutorService` in preference to `Timer`. – Brian Goetz Jun 22 '16 at 14:47
  • 1
    See also http://stackoverflow.com/questions/31482093/why-cant-functionalinterface-be-applied-to-a-sam-abstract-base-class/31491773#31491773 – Brian Goetz Jun 22 '16 at 18:46
  • @Zircon you're absolutely wrong. Have a look at this notation https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html#schedule(java.util.TimerTask,%20java.util.Date) . The real problem is that TimerTask is not a functional interface, or an interface at all, so it can not be expressed via lambda – Ben May 04 '18 at 23:41
  • @Ben this question is 2 years old... – dabadaba May 06 '18 at 09:40

2 Answers2

33

TimerTask is not a SAM (single abstract method) type -- now, that sounds contradictory, because there is only one abstract method on TimerTask! But because the abstract parent class implements cancel and scheduledExecutionTime, even though they're not abstract, the compiler can't go so far as to take your lambda and create an anonymous subtype of TimerTask.

What can be done is lambdas for interfaces that have a single abstract method and one or more default methods, but sadly TimerTask is an older class and doesn't use the default method capabilities of Java 8.

Thorn G
  • 12,620
  • 2
  • 44
  • 56
  • 4
    Any other "modern" alternative for setting timers that would be as concise as what I am trying to get to? – dabadaba Jun 22 '16 at 14:26
  • 3
    The term you're looking for is _functional interface_. – Brian Goetz Jun 22 '16 at 14:49
  • @BrianGoetz ah, did that totally supercede the "SAM" nomenclature? I guess I'm out of date. – Thorn G Jun 22 '16 at 14:50
  • @BrianGoetz Thank you, I wish I had that technical and terminological knowledge. I will try out `ScheduledExecutorService` as you suggested in your other comment. – dabadaba Jun 22 '16 at 14:50
  • 3
    @TomG Yes. We started with the idea of SAM types, there was an extensive debate within the Expert Group as to whether to support SAM abstract types (notably, TimerTask is really the only example that ever seems to comes up!), and after a lot of discussion, we concluded that supporting SAM abstract types introduced too much semantic complexity to carry its weight. Hence was born the term "functional interface". – Brian Goetz Jun 22 '16 at 16:00
  • 1
    This has been discussed [here](http://stackoverflow.com/q/31482093/2711488) and [here](http://stackoverflow.com/q/24610207/2711488). – Holger Jun 22 '16 at 16:48
  • In other words Java compiler writers are lazy again. – Daniel Sharp Nov 21 '18 at 10:11
28

In order to use lambda expression you need a target type which has to be a SAM type, i.e. functional interface. Since TimerTask is an abstract class you can't use lambdas here.
What you can do, to use lambda expressions, is to write an utility function which wraps your code into a TimerTask like:

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

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

Then you can use your lambda:

times.schedule(wrap(() -> tournaments.remove(id)), delay);
Flown
  • 11,480
  • 3
  • 45
  • 62