Search code examples
javafunctional-programmingtaskconsumer

When are java 8 consumers preferable over a runnable interface?


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?


Solution

  • 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.