How does java differentiate Callable and Runnable

2020-07-07 02:58发布

问题:

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 );
    }
}

回答1:

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

  • submit(Callable<T> task) using Callable<T> which has method call() returning T.
  • submit(Runnable task) usnig Runnable which has method run() returning nothing (void).

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() {
        // ...  
    }}
);


回答2:

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.