2

My question is in what situation or under what circumstances it would be better to use a callable interface over a simple one-method functional interface.

Say we have a game with a task-based event handling system. It cycles through a queue of events every second. Each event concerns one player. In what case would it be preferable to do

Consumer<Player> c1 = (player) -> player.sendMessage("hey"); 

over

Runnable r1 = () -> player.sendMessage("hey");

Just found this question: The difference between the Runnable and Callable interfaces in Java. It explained some points regarding multi-threaded environments but the situation I am illustrating concerns a single threaded environment. Would it still matter then?

  • 2
    Runnable is actually a functional interface, so your question is not clear. A Consumer takes one parameter, while a Runnable doesn't expect anything. Neither of them return a value. – fps Mar 27 '18 at 02:24

2 Answers2

7

I think you might be misunderstanding what 'functional interface' means. In Java, 'functional interface' has a very specific meaning: an interface with exactly one abstract method. The value of functional interfaces in the context of Java is their use in lambda expressions. An annotation has been added to denote interfaces that are explicitly designed to be functional. But it doesn't have any run-time semantic: any interface that meets the criteria is functional.

So, in fact, Runnable is a functional interface with a single abstract method run. Which makes your phrase "use a functional interface over for example a runnable interface" meaningless.

Java provides a whole host of pre-defined generic functional interfaces in the java.util.function package. These are purely for utility: to save you from having to create multiple interfaces which all do essentially the same thing.

My personal view is that these should be used sparingly. In your case the event handling system is presumably a key component of your system and having it hold objects implementing an Event interface will make your intent clearer than having it hold ObjLongConsumer<Player> or something similar even if your events turn out to be an interface that has the same signature.

Update:

in your comments you asked if there's a reason to make your Task interface generic if in all cases. No there is no reason. The only reason to make an interface or class generic is if it will be used in multiple contexts with different types. In your case if tasks will always involve a Player then make that a concrete part of the signature of the interface's method rather than a parameterised type.

sprinter
  • 27,148
  • 6
  • 47
  • 78
  • Whoops was misled than by the build in utility functional interfaces. Thanks for the clarification, the correct term would then be a callable? Also what about a task builder design, to pre-define tasks designed to invoke behavior from a player. In this case, is there any reason (beyond personal preference) to generify the task (Task) and then use a player consumer instead of a simple non-generic runnable interface? – Stan Van Der Bend Mar 27 '18 at 02:38
  • I think it’s slightly misleading to say “an interface with exactly one non-default method”. Well, an interface say with one static method is not functional but the way you’ve written your answer makes it seem like so. I’d stick to the normal terms and say “an interface with a SAM( single abstract method)” to remove any ambiguity. – Ousmane D. Mar 27 '18 at 07:43
  • @sprinter great! +1 :) – Ousmane D. Mar 27 '18 at 16:27
  • @StanVanDerBend I added an update to answer your question about whether to make Task generic – sprinter Mar 27 '18 at 21:02
0

As per Oracle documentation:

Functional interfaces often represent abstract concepts like functions, actions, or predicates. In documenting functional interfaces, or referring to variables typed as functional interfaces, it is common to refer directly to those abstract concepts, for example using "this function" instead of "the function represented by this object". When an API method is said to accept or return a functional interface in this manner, such as "applies the provided function to...", this is understood to mean a non-null reference to an object implementing the appropriate functional interface, unless potential nullity is explicitly specified. Functional interface are the interfaces that have only one functionality to implement. So basically, if you will see at runnable interface as well, it is again kind of function interface with only one functionality "run".

So, you can consider Functional Interface to be kind of category of interfaces with exactly one non default function and various interface like Runnable Interface and Comparable interface come under this category.

Moreover, in JAVA 8 you can also directly implement functional interface anonymously using lambda expressions:

Runnable r1 = () -> System.out.println("Hello World!");

Using lambda expressions, makes the code quite neat and readable and also reduces the number of line. Also, lambda expressions can help in sequential and parallel execution using Streams.

While using functional interface you can also ensure to have one non default function only so that it does not break in future modifications by implementing @FunctionalInterface.

For more details about Functional Interface you can visit here

Aman Chhabra
  • 3,824
  • 1
  • 23
  • 39
  • Are there cases though where doing `Consumer c1 = (player) -> player.sendMessage("hey");` is preferable over `Runnable r1 = () -> player.sendMessage("hey");` (in a single threaded environment.) – Stan Van Der Bend Mar 27 '18 at 02:47
  • 1
    There is no specific different in the above two shared statements.But, they have two different tasks to do. As per JAVA docs, Consumer interfaces are the one that should be used for lamda expressions for the cases where operation accepts a single input argument and returns no result. Whereas, runnable should be used to execute the tasks that accepts and returns no argument and is expected to be executed inside a thread – Aman Chhabra Mar 27 '18 at 02:58