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

В чем разница между Consumer и Supplier?

1.0 Junior🔥 241 комментариев
#Stream API и функциональное программирование

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

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

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

Consumer и Supplier: функциональные интерфейсы Java

Consumer и Supplier — это два базовых функциональных интерфейса из пакета java.util.function, которые часто используются в потоках обработки данных (Stream API) и функциональном программировании. Они имеют противоположное поведение: если Consumer принимает значение, то Supplier его производит.

Consumer: потребитель данных

Consumer — это функциональный интерфейс, который принимает один аргумент и не возвращает значение (возвращает void).

Сигнатура:

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

Примеры использования:

// Пример 1: Печать элементов списка
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
Consumer<String> printConsumer = name -> System.out.println(name);
names.forEach(printConsumer);

// Пример 2: Обновление объекта
Consumer<User> updateUser = user -> {
    user.setLastLoginTime(LocalDateTime.now());
    user.setLoginCount(user.getLoginCount() + 1);
};

User user = new User("john", "john@example.com");
updateUser.accept(user);

// Пример 3: Логирование в Stream API
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
    .filter(n -> n > 2)
    .peek(n -> System.out.println("Filtered: " + n))  // Consumer через peek()
    .map(n -> n * 2)
    .forEach(System.out::println);  // Consumer через forEach()

// Пример 4: Цепочка Consumer с andThen()
Consumer<String> logConsumer = msg -> System.out.println("[LOG] " + msg);
Consumer<String> alertConsumer = msg -> System.out.println("[ALERT] " + msg);

Consumer<String> chainedConsumer = logConsumer.andThen(alertConsumer);
chainedConsumer.accept("Error occurred");
// Вывод:
// [LOG] Error occurred
// [ALERT] Error occurred

Supplier: поставщик данных

Supplier — это функциональный интерфейс, который не принимает аргументов и возвращает значение.

Сигнатура:

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

Примеры использования:

// Пример 1: Ленивая инициализация объекта
Supplier<LocalDateTime> dateTimeSupplier = LocalDateTime::now;
LocalDateTime now = dateTimeSupplier.get();

// Пример 2: Создание экземпляра класса
Supplier<User> userSupplier = () -> new User("guest", "guest@example.com");
User newUser = userSupplier.get();

// Пример 3: Логирование с ленивым вычислением
class Logger {
    void debug(Supplier<String> messageSupplier) {
        if (isDebugEnabled()) {
            System.out.println(messageSupplier.get());
        }
    }
}

Logger logger = new Logger();
// Сообщение вычисляется только если debug включен
logger.debug(() -> "Expensive calculation: " + expensiveOperation());

// Пример 4: Stream API с генерацией значений
Supplier<Double> randomSupplier = Math::random;
Stream.generate(randomSupplier)
    .limit(5)
    .forEach(System.out::println);

Основные различия

ХарактеристикаConsumerSupplier
ПараметрыПринимает 1 аргумент (T)Не принимает аргументов
Возвращаемое значениеvoid (ничего не возвращает)T (возвращает значение)
РольПотребляет данныеПроизводит данные
Сигнатура методаvoid accept(T t)T get()
ПрименениеПобочные эффекты, логированиеЛенивая инициализация, фабрики

Вариации функциональных интерфейсов

// Для примитивных типов (оптимизация)
IntConsumer intConsumer = i -> System.out.println(i);
LongConsumer longConsumer = l -> System.out.println(l);

IntSupplier intSupplier = () -> 42;
DoubleSupplier doubleSupplier = () -> 3.14;

// Два параметра
BiConsumer<String, Integer> biConsumer = (name, age) -> 
    System.out.println(name + " is " + age + " years old");
biConsumer.accept("John", 30);

// С функцией
Function<Integer, Integer> doubleValue = x -> x * 2;
Function<Integer, String> toString = Object::toString;

Практический пример: обработка данных

public class DataProcessor<T> {
    private Supplier<List<T>> dataSource;
    private Consumer<T> processor;
    
    public DataProcessor(Supplier<List<T>> dataSource, Consumer<T> processor) {
        this.dataSource = dataSource;
        this.processor = processor;
    }
    
    public void process() {
        // Supplier получает данные
        List<T> data = dataSource.get();
        
        // Consumer обрабатывает каждый элемент
        data.forEach(processor);
    }
}

// Использование
Supplier<List<User>> userLoader = () -> userRepository.findAll();
Consumer<User> emailSender = user -> sendEmail(user.getEmail());

DataProcessor<User> processor = new DataProcessor<>(userLoader, emailSender);
processor.process();

Consumer и Supplier — это строительные блоки функционального программирования в Java. Consumer используется для выполнения действий над данными, а Supplier — для производства данных. Правильное их применение делает код более читаемым, модульным и функциональным.

В чем разница между Consumer и Supplier? | PrepBro