Stream API и Lambda

Базовый Java
≈ 2 мин чтения

Поведение как часть программы

До этого момента код в основном отвечал на вопрос «какие данные у нас есть и какие методы их обрабатывают». В этом разделе появится ещё одна важная идея: само действие можно передавать как значение, а обработку последовательности данных — описывать как цепочку шагов. Именно на этом строятся lambda-выражения и Stream API.

После раздела привычная задача вроде «взять список, оставить подходящие элементы, преобразовать их и получить результат» будет читаться как последовательный сценарий, а не как набор вложенных циклов и временных коллекций.

Что будет внутри раздела

  • Lambda-выражения. Научимся компактно описывать небольшое поведение прямо в месте использования.
  • Функциональные интерфейсы. Разберём типы, в которые помещаются lambda-выражения, и стандартные интерфейсы из java.util.function.
  • Ссылки на методы. Увидим короткую запись для случаев, когда lambda только вызывает уже существующий метод или конструктор.
  • Основы Stream API. Разберём источник, pipeline, ленивое выполнение и отличие stream от коллекции.
  • Промежуточные операции. Научимся фильтровать, преобразовывать, сортировать и ограничивать поток данных.
  • Терминальные операции. Посмотрим, как pipeline запускается и превращается в число, значение, коллекцию или побочный эффект.
  • Collectors. Соберём результаты в более сложные структуры: строки, группы и отображения.
  • Optional. Разберём явное представление ситуации, когда результат может отсутствовать.
  • Примитивные стримы. Познакомимся с IntStream, LongStream и DoubleStream.
  • Параллельные стримы. Поймём, что меняется при параллельном выполнении и почему оно подходит далеко не каждой задаче.

Темы идут в этом порядке не случайно. Сначала нужно научиться передавать поведение, затем понять типы этого поведения, а уже после — использовать его в stream-pipeline. В конце раздела мы добавим инструменты для сборки результатов, отсутствующих значений, примитивов и параллельного выполнения.

List<String> names = List.of("Ann", "Bob", "Alexander");

List<String> result = names.stream()
        .filter(name -> name.length() > 3)
        .map(String::toUpperCase)
        .toList();

Пока достаточно увидеть общую форму: данные проходят через несколько понятных шагов, а в конце получается новый результат. Как именно работает каждый элемент этой цепочки, будем разбирать последовательно на следующих страницах.