Может ли один класс реализовать оба интерфейса: Runnable и Callable?

«Может ли один класс реализовать оба интерфейса: Runnable и Callable?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, может. Один класс может реализовать как Runnable, так и Callable<V>. Это два отдельных интерфейса для представления задач в многопоточности.

Различия интерфейсов: Критерий Runnable Callable<V>
Возвращаемое значение void Тип V (обобщенный)
Исключения Не может бросать проверяемые (checked) исключения Может бросать Exception
Запуск Передается в Thread или ExecutorService.execute() Передается в ExecutorService.submit()

Пример класса, реализующего оба интерфейса:

import java.util.concurrent.Callable;

public class DualTask implements Runnable, Callable<String> {
    private final String data;

    public DualTask(String data) { this.data = data; }

    @Override
    public void run() {
        // Логика для Runnable
        System.out.println("Processing (Runnable): " + data);
    }

    @Override
    public String call() throws Exception {
        // Логика для Callable, может вернуть результат и бросить исключение
        if (data == null) throw new IllegalArgumentException("Data is null");
        return "Processed (Callable): " + data.toUpperCase();
    }
}

Использование:

DualTask task = new DualTask("test");

// Как Runnable
new Thread(task).start();
// Или
executorService.execute(task);

// Как Callable
Future<String> future = executorService.submit(task); // Здесь task используется как Callable
String result = future.get(); // result = "Processed (Callable): TEST"

Важно: Класс FutureTask (часто используемая обертка) может принимать Callable в конструкторе и сам реализует Runnable, но это не стандартный класс, реализующий оба интерфейса "напрямую".