Небольшая статья с примерами использования Stream API  Java.

Часто  в Java Stream API используется для работы с коллекциями, позволяя писать код в функциональном стиле.

Итак, что такое Stream API в Java 8? «Package java.util.stream» — «Classes to support functional-style operations on streams of elements, such as map-reduce transformations on collections». Попробую дать свой вариант перевода, фактически это — поддержка функционального стиля операций над потоками, такими как обработка и «свёртка» обработанных данных.
«Stream operations are divided into intermediate and terminal operations, and are combined to form stream pipelines. A stream pipeline consists of a source (such as a Collection, an array, a generator function, or an I/O channel); followed by zero or more intermediate operations such as Stream.filter or Stream.map; and a terminal operation such as Stream.forEach or Stream.reduce» — описание с сайта.
Попробуем разобраться в этом определении. Авторы говорят нам о наличии промежуточных и конечных операций, которые объедены в форму конвейеров. Потоковые конвейеры содержат источник (например, коллекции и т.п.), за которым следуют промежуточные и конечные операции и приводятся их примеры. Тут стоит заметить, что все промежуточные операции над потоками — ленивые(LAZY). Они не будут исполнены, пока не будет вызвана терминальная (конечная) операция.

Еще одна интересная особенность — это наличие метода parallelStream(). Данные возможности я использую для улучшения производительности при обработке больших объемов данных. Параллельные потоки позволят ускорить выполнение некоторых видов операций. Я использую данную возможность, когда знаю, что коллекция достаточно большая для обработки ее в «ForkJoin» варианте. Подробнее про Fork/Join читайте в предыдущей статье на эту тему — «Java 8 в параллель. Учимся создавать подзадачи и контролировать их выполнение».

Закончим с теоретической частью и перейдем к несложным примерам.
Пример показывает нахождение максимального и минимального значения из коллекции.

Немного усложним пример и добавим исключения (в виде null) при максимального значения в пример №2.

Усложним примеры.

Создадим коллекцию «Спортивный лагерь», состоящую из полей «Имя» и «Количество дней в спортивном лагере». Сам пример создания класса ниже:

А теперь примеры работы с новыми данными:

В примере было найдено имя, Ирина, которая будет находиться в лагере дольше всех.
Преобразуем пример и создадим ситуацию, когда у нас вкралась ошибка, и одна из записей null в имени.

В этом случае вы получите результат, равный «Name=null».Согласитесь, что мы хотели не этого.Немного изменим поиск по коллекции на новый вариант.

Полученный результат, «Ira» — верен.
В примерах показано нам нахождение минимальных и максимальных значений по коллекциям с небольшими дополнениями в виде исключения null значений.
Как мы говорили доступные методы можно разделить на две большие группы промежуточные операции и конечные. Авторы могут называть их различно, например, вариант названия конвейерные и терминальные методы употребляется в литературе и статьях. При работе с методами существует одна конструктивная особенность, вы можете «накидывать» множество промежуточных операций, в конце производя вызов одного терминального метода.
В новом примере добавим сортировку и вывод определенного элемента, например, добавим фильтр по именам с встречающимся «Ivan» и произведем подсчет таких элементов (исключим null значения).

Добавив в коллекцию new SportsCamp(«Ivan», 17), получим результат равный «countName=2». Нашли две записи.
В данных примерах использовалось создание стрима из коллекции, доступны и другие варианты, например, создание стрима из требуемых значений, например, Stream streamFromValues = Stream.of(«test1», «test2», «test3»), возможны и другие варианты.
Как говорилось выше, у пользователей есть возможность использовать «обработку» используя parallelStream().
Немного изменив пример, получим новый вариант реализации:

Особенность этого варианта состоит в реализации параллельного стрима. Хочется обратить внимание, что parallelStream() оправданно использовать на мощных серверах(многоядерных) для больших коллекций. Я не даю четкого определения и точного размера коллекций, т.к. очень много параметров необходимо выявить и просчитать. Часто только тестирование может показать вам увеличение производительность.
Мы немного познакомились с простыми операциями, поняли отличие между конвейерными и терминальными операциями, попробовали и те и другие. А теперь давайте посмотрим примеры более сложных операций, например, collect и Map, Flat и Reduce.
Еще раз заглянем в официальную документацию документацию и попробуем реализовать свои примеры.
В новом примере попробуем преобразовать одну коллекцию в другую, по именам начинающимся с «I» и запишем это в List.

Результат будет равен трём. Тут нужно обратить внимание, что порядок указания исключения null элементов значим.
Обратите внимание, что Collectors обладает массой возможностей, включая вывод среднего значения или информации со статистикой. Как пример, попробуем соединить данные, вот так:

Результат:«In camp Ivan and Petr and Ivan and Ira rest all days ». Есть несколько вариантов использования Collectors.joining.

Из Map, Flat и Reduce остановимся на примере с reduce. Map и flat-map будут рассмотрены в следующих статьях.
Reduce используется для «сборки» элементов, простым языком, если вы хотите в потоке произвести создание нового экземпляра объекта с агрегирующими показателями других элементов, то reduce вам подойдет. Существует несколько вариантов использования. Рассмотрим один из них, например, произведем суммирование данных по всем дням пребывания в спортивном лагере.

В это варианте reduce принимает три значения, первый – идентификатора, второй – аккумулятор, а третий это – фактически «объедение». Существуют и несколько других вариантов.

В статье описана лишь небольшая часть методов Stream Apo, возможно, они заинтересуют многих и появятся в новых проектах. В совокупности с лямбдами функционал становится отличным инструментом для написания краткого и быстрого кода. Всем удачи.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Навигация по записям