Какие знаешь интерфейсы похожие на Runnable?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Интерфейсы похожие на 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 — для ленивых вычислений
Выбор зависит от задачи: нужен ли результат, исключения, асинхронность?