9

I got this little code to test out Callable. However, I find it pretty confusing how the Compiler could know if the Lambda is for the Interface Callable or Runnable since both don't have any parameter in their function.

IntelliJ, however, shows that the Lambda employs the code for a Callable.

public class App {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(() ->{
            System.out.println("Starting");
            int n = new Random().nextInt(4000);
            try {
                Thread.sleep(n);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                System.out.println("Finished");
            }
            return n;
        });
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.MINUTES );
    }
}
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
curiouscupcake
  • 1,157
  • 13
  • 28
  • 2
    It returns a result, which Runnable doesn't, so it's a Callable. – Michael Aug 14 '18 at 19:35
  • 3
    The key phrases in the language spec are "void compatible" and "value compatible". – Andy Turner Aug 14 '18 at 19:35
  • @Michael that's a simplistic explanation: you can use some lambdas which return values as runnables (e.g. `() -> Integer.valueOf(0)`), in which case the return value is discarded. – Andy Turner Aug 14 '18 at 19:40
  • 2
    @AndyTurner That's an expression lambda, which OP is not using, and the rules are different. You can't write the keyword `return` and have the result be ignored. – Michael Aug 14 '18 at 19:46

2 Answers2

11

See the documentation of ExecutorService which has 2 submit methods with one parameter:

Your lambda gives an output, returns something:

executorService.submit(() -> {
    System.out.println("Starting");
    int n = new Random().nextInt(4000);
    // try-catch-finally omitted
    return n;                                      // <-- HERE IT RETURNS N
});

So the lambda must be Callable<Integer> which is a shortcut for:

executorService.submit(new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        System.out.println("Starting");
        int n = new Random().nextInt(4000);
        // try-catch-finally omitted
        return n;  
    }}
);

To compare, try the same with Runnable and you see it's method's return type is void.

executorService.submit(new Runnable() {
    @Override
    public void run() {
        // ...  
    }}
);
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • confusing: "**three** `submit` methods with one parameter" but you only listed 2...(did you mean 2, since I believe there are only 2 with 1 parameter) – user85421 Aug 14 '18 at 20:21
  • @CarlosHeuberger: It's a typo. I meant to list all the 3 `submit` methods, however then I recognized that only 2 make sense and left "3" accidentally. Thank you. – Nikolas Charalambidis Aug 14 '18 at 20:22
  • Hmmmm, this gives me mixed feelings. I'm glad we can use the shrothand syntax but when things become too indirect I feel like I'm not in control of what I'm writing. – Sridhar Sarnobat Dec 14 '22 at 23:04
3

The main difference in the signature is that a Callable returns a value while a Runnabledoes not. So this example in your code is a Callable, but definately not a Runnable, since it returns a value.

Dorian Gray
  • 2,913
  • 1
  • 9
  • 25