I've been switching over to Java from C# after some recommendations from some over at CodeReview. So, when I was looking into LWJGL, one thing I remembered was that every call to Display
must be executed on the same thread that the Display.create()
method was invoked on. Remembering this, I whipped up a class that looks a bit like this.
public class LwjglDisplayWindow implements DisplayWindow {
private final static int TargetFramesPerSecond = 60;
private final Scheduler _scheduler;
public LwjglDisplayWindow(Scheduler displayScheduler, DisplayMode displayMode) throws LWJGLException {
_scheduler = displayScheduler;
Display.setDisplayMode(displayMode);
Display.create();
}
public void dispose() {
Display.destroy();
}
@Override
public int getTargetFramesPerSecond() { return TargetFramesPerSecond; }
@Override
public Future<Boolean> isClosed() {
return _scheduler.schedule(() -> Display.isCloseRequested());
}
}
While writing this class you'll notice that I created a method called isClosed()
that returns a Future<Boolean>
. This dispatches a function to my Scheduler
interface (which is nothing more than a wrapper around an ScheduledExecutorService
. While writing the schedule
method on the Scheduler
I noticed that I could either use a Supplier<T>
argument or a Callable<T>
argument to represent the function that is passed in. ScheduledExecutorService
didn't contain an override for Supplier<T>
but I noticed that the lambda expression () -> Display.isCloseRequested()
is actually type compatible with both Callable<bool>
and Supplier<bool>
.
My question is, is there a difference between those two, semantically or otherwise – and if so, what is it, so I can adhere to it?
Best Answer
The short answer is that both are using functional interfaces, but it's also worthy to note that not all functional interfaces must have the
@FunctionalInterface
annotation. The critical part of the JavaDoc reads:And the simplest definition of a functional interface is (simply, without other exclusions) just:
Therefore, in @Maciej Chalapuk's answer, it is also possible to drop the annotation and specify the desired lambda:
Now, what makes both
Callable
andSupplier
functional interfaces is because they do contain exactly one abstract method:Callable.call()
Supplier.get()
Since both methods do not take in an argument (as opposed to the
MyInterface.myCall(int)
example), the formal parameters are empty (()
).As you should be able to infer by now, that is just because both abstract methods will return the type of the expression you use. You should definitely be using a
Callable
given your usage of aScheduledExecutorService
.Further exploration (beyond the scope of the question)
Both interfaces comes from entirely different packages, hence they are used differently too. In your case, I don't see how an implementation of
Supplier<T>
will be used, unless it is supplying aCallable
:The first
() ->
can be loosely interpreted as "aSupplier
gives..." and the second as "aCallable
gives...".return value;
is the body of theCallable
lambda, which itself is the body of theSupplier
lambda.However, usage in this contrived example gets slightly complicated, as you now need to
get()
from theSupplier
first beforeget()
-ting your result from theFuture
, which will in turncall()
yourCallable
asynchronously.