С каким функциональным интерфейсом работает метод map в Stream API?

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

Ответ

Метод map() в java.util.stream.Stream работает с функциональным интерфейсом java.util.function.Function<T, R>.

Детали интерфейса Function<T, R>:

  • Абстрактный метод: R apply(T t) — принимает аргумент типа T и возвращает результат типа R.
  • Назначение в map(): Задать правило преобразования каждого элемента исходного потока (Stream<T>) в элемент нового потока (Stream<R>).

Почему это важно? Использование стандартного интерфейса Function обеспечивает совместимость с лямбда-выражениями и ссылками на методы, что делает код лаконичным.

Пример с лямбдой и ссылкой на метод:

List<String> names = List.of("John", "Alice", "Bob");

// Использование лямбда-выражения
List<String> upperNames1 = names.stream()
    .map(name -> name.toUpperCase()) // Function<String, String>
    .toList();

// Использование ссылки на метод (более идиоматично)
List<String> upperNames2 = names.stream()
    .map(String::toUpperCase) // Тот же Function<String, String>
    .toList();

Ключевые свойства map():

  1. Не модифицирует источник: Работает по принципу immutability.
  2. Ленивая операция: Вычисление происходит только при вызове терминальной операции (например, collect() или toList()).
  3. Сохраняет порядок: В последовательных потоках порядок элементов сохраняется.