Основы Stream API

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

Stream описывает обработку данных

Stream — не новая коллекция и не контейнер, в котором хранятся элементы. Это объект, описывающий последовательность вычислений над источником данных. Источником может быть, например, коллекция, массив или специально созданный stream.

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

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

В этой цепочке names остаётся обычным списком. stream() создаёт stream над его элементами, затем описываются шаги обработки, а toList() получает итоговый результат. Исходная коллекция при этом не изменяется.

Pipeline: источник, промежуточные шаги, терминал

Типичный stream-pipeline состоит из трёх частей:

  • источник — откуда приходят элементы;
  • промежуточные операции — как элементы фильтруются или преобразуются;
  • терминальная операция — какой результат нужно получить.

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

Stream ленивый

Stream<String> stream = names.stream()
        .filter(name -> {
            System.out.println("check: " + name);
            return name.length() > 3;
        });

System.out.println("pipeline created");
long count = stream.count();

Сообщения check: ... начнут появляться только во время count(). До терминальной операции pipeline лишь описан. Позже отдельно разберём, какие операции являются промежуточными, а какие терминальными.

Stream используется один раз

После терминальной операции stream считается потреблённым. Нельзя сохранить его в переменную, вызвать count(), а затем попытаться пройти тем же stream ещё раз. Если обработка нужна повторно, создаётся новый stream из источника.

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