← Назад к вопросам

Какие знаешь интерфейсы похожие на Runnable?

1.0 Junior🔥 171 комментариев
#Многопоточность#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Интерфейсы похожие на Runnable в Java

Runnable — это функциональный интерфейс для выполнения кода в отдельном потоке. В Java есть множество похожих интерфейсов с похожей функциональностью:

1. Runnable (Базовый)

Выполняет код без параметров и возвращаемого значения:

public interface Runnable {
    void run();
}

// Использование
public class RunnableExample {
    public static void main(String[] args) {
        // Lambda выражение
        Runnable task = () -> {
            System.out.println("Задача выполняется в потоке: " + 
                Thread.currentThread().getName());
        };
        
        // Выполнение в новом потоке
        Thread thread = new Thread(task);
        thread.start();
        
        // Или через executor
        ExecutorService executor = Executors.newSingleThreadExecutor();
        executor.execute(task);
        executor.shutdown();
    }
}

2. Callable (С возвращаемым значением)

В отличие от Runnable, Callable возвращает результат и может выбросить исключение:

public interface Callable<V> {
    V call() throws Exception;
}

// Использование
public class CallableExample {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // Callable с возвращаемым значением
        Callable<Integer> task = () -> {
            System.out.println("Callable выполняется");
            Thread.sleep(2000);
            return 42;  // Возвращаем результат
        };
        
        // Использование с ExecutorService
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(task);
        
        // Блокирующее ожидание результата
        Integer result = future.get();  // Вернёт 42 после 2 секунд
        System.out.println("Результат: " + result);
        
        // Проверка завершения без блокировки
        if (future.isDone()) {
            System.out.println("Задача завершена");
        }
        
        executor.shutdown();
    }
}

Ключевое отличие: Callable может возвращать значение и выбросить checked exception:

// Runnable — нельзя выбросить checked exception
Runnable badRunnable = () -> {
    // ❌ Компилятор ошибка!
    // throw new IOException();  
};

// Callable — можно выбросить exception
Callable<Void> goodCallable = () -> {
    // ✅ Разрешено
    throw new IOException();  
};

3. Future и FutureTask

Представляет результат асинхронного вычисления:

public class FutureExample {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        
        // Создание task'ов
        Callable<String> task1 = () -> {
            Thread.sleep(2000);
            return "Результат задачи 1";
        };
        
        Callable<String> task2 = () -> {
            Thread.sleep(1000);
            return "Результат задачи 2";
        };
        
        // Отправка на выполнение
        Future<String> future1 = executor.submit(task1);
        Future<String> future2 = executor.submit(task2);
        
        // Ждём результата
        System.out.println(future2.get());  // Вернёт после 1 сек
        System.out.println(future1.get());  // Вернёт после 2 сек
        
        // Отмена задачи
        future1.cancel(true);  // true = interrupt если работает
        
        executor.shutdown();
    }
}

// FutureTask — комбинация Runnable и Future
public class FutureTaskExample {
    public static void main(String[] args) throws Exception {
        Callable<Integer> task = () -> {
            System.out.println("FutureTask работает");
            return 100;
        };
        
        FutureTask<Integer> futureTask = new FutureTask<>(task);
        
        // FutureTask implements Runnable
        Thread thread = new Thread(futureTask);
        thread.start();
        
        // Получить результат
        Integer result = futureTask.get();  // 100
        System.out.println("Результат: " + result);
    }
}

4. Consumer (Функциональный интерфейс)

Принимает параметр, ничего не возвращает (void):

public interface Consumer<T> {
    void accept(T t);
}

// Использование
public class ConsumerExample {
    public static void main(String[] args) {
        Consumer<String> printConsumer = str -> System.out.println(str);
        
        // С foreach
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        names.forEach(printConsumer);
        
        // С streams
        names.stream()
            .filter(name -> name.length() > 3)
            .forEach(printConsumer);
    }
}

5. Supplier (Функциональный интерфейс)

Не принимает параметров, возвращает значение:

public interface Supplier<T> {
    T get();
}

// Использование
public class SupplierExample {
    public static void main(String[] args) {
        // Ленивое вычисление
        Supplier<LocalDateTime> timeSupplier = () -> LocalDateTime.now();
        
        System.out.println("Время 1: " + timeSupplier.get());
        Thread.sleep(1000);
        System.out.println("Время 2: " + timeSupplier.get());  // Новое значение
        
        // С CompletableFuture
        CompletableFuture<String> future = CompletableFuture.supplyAsync(
            () -> "Результат из supplier"
        );
        System.out.println(future.get());
    }
}

6. Function и BiFunction

Применить функцию к аргументам:

public interface Function<T, R> {
    R apply(T t);
}

public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}

// Использование
public class FunctionExample {
    public static void main(String[] args) {
        Function<String, Integer> stringLength = String::length;
        BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b;
        
        System.out.println(stringLength.apply("Hello"));  // 5
        System.out.println(sum.apply(10, 20));            // 30
        
        // С streams
        List<String> names = Arrays.asList("Alice", "Bob");
        names.stream()
            .map(stringLength)
            .forEach(System.out::println);
    }
}

7. Action (Android, но аналогично)

Выполнить действие без параметров и возвращаемого значения:

// Пример из RxJava (реактивное программирование)
public interface Action {
    void run() throws Exception;
}

// Использование в RxJava
public class RxJavaExample {
    public static void main(String[] args) {
        Observable.create(emitter -> {
            emitter.onNext("Hello");
            emitter.onComplete();
        })
        .doOnComplete(() -> System.out.println("Завершено"))
        .subscribe(
            item -> System.out.println(item),  // Consumer
            error -> System.err.println(error), // Consumer<Throwable>
            () -> System.out.println("Done")    // Action
        );
    }
}

8. Predicate

Проверить условие (возвращает boolean):

public interface Predicate<T> {
    boolean test(T t);
}

// Использование
public class PredicateExample {
    public static void main(String[] args) {
        Predicate<Integer> isEven = n -> n % 2 == 0;
        Predicate<String> isLonger = s -> s.length() > 3;
        
        System.out.println(isEven.test(4));      // true
        System.out.println(isLonger.test("Hi")); // false
        
        // С streams
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
        numbers.stream()
            .filter(isEven)
            .forEach(System.out::println);
    }
}

9. CompletableFuture (Асинхронные операции)

Мощный инструмент для асинхронного выполнения:

public class CompletableFutureExample {
    public static void main(String[] args) throws Exception {
        // Создание асинхронной задачи
        CompletableFuture<String> future = CompletableFuture
            .supplyAsync(() -> {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return "Результат";
            })
            .thenApply(result -> result + " обработано")
            .thenAccept(result -> System.out.println(result));
        
        // Блокирующее ожидание
        future.join();  // или future.get()
        
        // Обработка исключений
        CompletableFuture<String> withError = CompletableFuture
            .supplyAsync(() -> {
                throw new RuntimeException("Ошибка!");
            })
            .exceptionally(ex -> "Обработана ошибка: " + ex.getMessage());
        
        System.out.println(withError.get());
    }
}

10. UnaryOperator и BinaryOperator

Операторы для преобразований:

public interface UnaryOperator<T> extends Function<T, T> {
    // Входной и выходной типы - одинаковые
}

public interface BinaryOperator<T> extends BiFunction<T, T, T> {
    // Два входа и выход - одного типа
}

// Использование
public class OperatorExample {
    public static void main(String[] args) {
        UnaryOperator<Integer> square = x -> x * x;
        BinaryOperator<Integer> sum = Integer::sum;
        
        System.out.println(square.apply(5));      // 25
        System.out.println(sum.apply(10, 20));    // 30
    }
}

Сравнительная таблица

ИнтерфейсПараметрыВозвращаетИсключенияИспользование
RunnableНетvoidНетПотоки
CallableНетДаДаExecutor'ы
ConsumerДаvoidНетforEach, streams
SupplierНетДаНетЛенивые вычисления
FunctionДаДаНетmap, streams
PredicateДаbooleanНетfilter, streams
Future-Результат-Асинхронность
CompletableFuture-РезультатДаСложные async

Best Practices

public class BestPractices {
    // 1. ✅ Используй Callable вместо Runnable если нужен результат
    // 2. ✅ Используй CompletableFuture для сложных асинхронных операций
    // 3. ✅ Используй функциональные интерфейсы (Consumer, Function) в streams
    // 4. ✅ Используй Future.get() с timeout для избежания зависания
    // 5. ✅ Обрабатывай исключения в Callable
    // 6. ❌ Не блокируй основной поток (main thread)
    // 7. ✅ Используй ExecutorService правильно (shutdown/awaitTermination)
}

Вывод

Runnable — это базовый интерфейс для потоков, но существуют более полнофункциональные альтернативы:

  • Callable — если нужен результат и исключения
  • Future/FutureTask — если нужно получить результат асинхронно
  • CompletableFuture — для сложных асинхронных операций
  • Consumer/Function/Predicate — для функционального программирования
  • Supplier — для ленивых вычислений

Выбор зависит от задачи: нужен ли результат, исключения, асинхронность?

Какие знаешь интерфейсы похожие на Runnable? | PrepBro