Интерфейс Consumer в Java - Вопросы
Всего: 5 вопросов
1. Когда используется интерфейс java.util.function.Consumer?
Когда используется интерфейс java.util.function.Consumer?
Consumer<T> используется тогда, когда объект нужно принять на вход и выполнить над ним действие, ничего не возвращая. Его функциональный дескриптор — T -> void, единственный абстрактный метод — void accept(T t). Смысл интерфейса — побочный эффект: вывод на консоль, запись в лог, изменение состояния объекта, отправка сообщения. Печать в консоль — лишь самый наглядный частный случай; на практике Consumer чаще встречается в сигнатурах методов JDK: Iterable.forEach(), Stream.forEach(), Stream.peek(), Optional.ifPresent(). Если действие должно вернуть значение, нужен не Consumer, а Function.
2. Напишите лямбда-выражение с использованием интерфейса java.util.function.Consumer, которое выводит данные объекта Exam.
public class Exam {
private final String name;
private final String version;
public Exam(String name, String version) {
this.name = name;
this.version = version;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
}
Напишите лямбда-выражение с использованием интерфейса java.util.function.Consumer, которое выводит данные объекта Exam.
public class Exam {
private final String name;
private final String version;
public Exam(String name, String version) {
this.name = name;
this.version = version;
}
public String getName() {
return name;
}
public String getVersion() {
return version;
}
}Тип-параметр Consumer — это любой ссылочный тип, в том числе ваш собственный класс:
Consumer<Exam> printExam = e -> System.out.println(e.getName() + " " + e.getVersion());
printExam.accept(new Exam("Java Core", "21")); // Java Core 21
printExam.accept(new Exam("Spring", "6")); // Spring 6
Лямбда получает объект Exam, печатает его поля и ничего не возвращает — ровно то, что описывает дескриптор T -> void.
3. Какой метод по умолчанию есть у интерфейса Consumer и как он работает?
Какой метод по умолчанию есть у интерфейса Consumer и как он работает?
У Consumer ровно один метод по умолчанию — andThen():
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
Он возвращает новый составной Consumer, который выполняет два действия подряд над одним и тем же аргументом, строго слева направо. Исходный Consumer при этом не меняется, поэтому результат нужно сохранить или использовать сразу. Исключения не перехватываются: если первое действие бросило исключение, второе не выполнится. Передача null в andThen() сразу приводит к NullPointerException из-за Objects.requireNonNull().
4. Чем Consumer отличается от Supplier, Function и Runnable?
Чем Consumer отличается от Supplier, Function и Runnable?
Различие только в наличии входа и выхода:
Consumer<T> void accept(T t) // T -> void
Supplier<T> T get() // void -> T
Function<T, R> R apply(T t) // T -> R
Runnable void run() // void -> void
Consumer принимает аргумент и ничего не возвращает, Supplier наоборот — аргументов нет, значение возвращается, Function принимает аргумент и возвращает результат, Runnable не принимает и не возвращает ничего. Все четыре интерфейса не хранят состояния и описывают ровно одно действие. Признак неверного выбора: внутри Consumer появляется запись во внешний список или поле, чтобы «вынести» результат наружу — в этом случае нужен Function и map() вместо forEach().
5. Какие «родственники» есть у Consumer в пакете java.util.function и зачем они нужны?
Какие «родственники» есть у Consumer в пакете java.util.function и зачем они нужны?
Одна разновидность для двух аргументов и несколько для примитивов — последние избавляют от автоупаковки:
BiConsumer<T, U> void accept(T t, U u) // (T, U) -> void, например Map.forEach()
IntConsumer void accept(int value) // int -> void, IntStream.forEach()
LongConsumer void accept(long value) // long -> void
DoubleConsumer void accept(double value) // double -> void
ObjIntConsumer<T> void accept(T t, int value) // (T, int) -> void, аккумуляторы в collect()
У BiConsumer, IntConsumer, LongConsumer и DoubleConsumer тоже есть andThen() — с параметром того же типа. У ObjIntConsumer и его аналогов метода andThen() нет.
IntConsumer printSquare = n -> System.out.println(n * n);
IntStream.rangeClosed(1, 3).forEach(printSquare);
// 1
// 4
// 9