2

Java 8 introduced lambda expressions together with the package java.util.function. This Package consists basically of standard interfaces for

I was wondering why there's no standard interface for a classic callback: Zero arguments and no return value:

  • Callback: () -> void

Example implementation:

@FunctionalInterface
interface Callback {

    void call();

    default Callback andThen(Callback after) {
        Objects.requireNonNull(after);
        return () -> {
            call();
            after.call();
        };
    }
}

Example use case:

MyTask task = new MyTask();
AtomicInteger finishedTasks = new AtomicInteger();
task.finished(() -> System.out.println(finishedTasks + " tasks finished"));
task.finished(() -> schedule(task, 1, TimeUnit.HOURS));
schedule(task, 1, TimeUnit.HOURS));

The closest interface would be Runnable but that's a bit too much related to multithreading.

My questions:

  • Do you know if Java provides this interface?
  • Where do I find a list of classes that are annotated with @FunctionalInterface?
steffen
  • 16,138
  • 4
  • 42
  • 81
  • 7
    You already have `Runnable`. – assylias Oct 22 '14 at 09:43
  • 4
    `Runnable` is just an interface located in the `java.lang` package and is not intrinsically linked to multithreading. – Benjamin Gale Oct 22 '14 at 09:46
  • "Where do I find a list of classes that are annotated with @FunctionalInterface" In Eclipse: Find one class that has it (like Supplier), highlight it, and do "Search -> References -> Workspace" or Ctrl+Shift+g – tobias_k Oct 22 '14 at 09:53
  • @BenjaminGale See the Javadoc for `Runnable`, it doesn't sound at all accurate for this use case; if this is the answer, Oracle should have changed the Javadoc for `Runnable` and `run()`. Also, we'd miss the `andThen` feature which I pinched from the `Consumer` interface. – steffen Oct 22 '14 at 10:19
  • @tobias_k Thanks! Unfortunately not all classes are annotated with `@FunctionalInterface`, see http://docs.oracle.com/javase/8/docs/api/java/awt/event/ActionListener.html for example. – steffen Oct 22 '14 at 10:25
  • @Holger my comment was in response to the comment in the post which states "The closest interface would be Runnable but that's a bit too much related to multithreading." `Runnable` is an interface so has no behaviour; it is purely a contract. Just because it happens to be used primarily by the threading classes does not mean it can **only** be used by those classes. – Benjamin Gale Oct 22 '14 at 10:29
  • @BenjaminGale Although you are (technically) right, I still would advise against using a `Runnable` as a method argument for this. Reading such code will surely make me wonder what that method has to do with threading. This is all about readable code. – Seelenvirtuose Oct 22 '14 at 10:35
  • @BenjaminGale My point is that it's not primarily *used* by threading classes. Its *purpose* is threading (read the Javadoc!). – steffen Oct 22 '14 at 10:37
  • 1
    What’s wrong with “[The general contract of the method `run` is that it may take any action whatsoever](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html#run--)”? To answer the question, how to “find a list of classes that are annotated with @FunctionalInterface”, [that’s an intrinsic feature of JavaDoc](http://docs.oracle.com/javase/8/docs/api/java/lang/class-use/FunctionalInterface.html)… – Holger Oct 22 '14 at 10:43
  • 1
    @Seelenvirtuose: if you stumble over a parameter type being `Runnable` then most probably it’s the *name* of the method which is too meaningless. Does it confuse you if you see code like [`stream.onClose(()->{/*action*/})`](http://docs.oracle.com/javase/8/docs/api/java/util/stream/BaseStream.html#onClose-java.lang.Runnable-)? If in doubt you can always add a documentation comment… – Holger Oct 22 '14 at 10:50
  • 1
    @Holger I think you're misreading that postscript. The meaning here is that concrete `run` implementations (which *are* "executed by a thread", typically passed to `new Thread().start()`, etc.) are of general case. But we should probably stop here now since we're getting too much into 'in-my-opinion-commotions'. I'll just write my interface as originally posted in order to conform with documentation and code semantics. – steffen Oct 22 '14 at 11:01
  • 1
    @steffen: Every method of every class is “executed by a thread”. `Runnable`s are not only passed to `new Thread(…)` but also to, e.g. `Stream.onClose(…)`, `SwingUtilities.invokeLater(…)` or `Executor.execute(…)`, where the latter’s documentation explicitly mentions the possibility of an execution within the caller’s thread for whatever purpose. Of course, you can define your own interface having a more specific purpose and name, there’s nothing wrong with that. Especially as Java 8 makes it easy to convert existing `Runnable`’s to another functional interface having the same signature. – Holger Oct 22 '14 at 11:15
  • The "executed by a thread" piece is quoted from the `Runnable` Javadoc and makes only sense to me if they meant "executed by an instance of `Thread`". – steffen Oct 22 '14 at 11:20
  • 5
    @steffen: Let it go. The EG discussed this in some detail and concluded that it was better to coopt `Runnable` than to create the opportunity for confusion because there were two competing abstractions. In a perfect world, we might have rewritten the Javadoc to reflect that its use had (long ago) become broader than was imagined in 1995, but the reality is that well before 2014 it became broadly understood that `Runnable` was the JDK's primary "task" abstraction, regardless of its connection with threads. – Brian Goetz Oct 22 '14 at 17:59

0 Answers0