Использовали ли вы Streams API в Java?

Использовали ли вы Streams API в Java?

15 марта 2022 г.

Прежде чем читать это, я бы порекомендовал попробовать и изучить, что такое императивный и декларативный стили программирования. См. [Императивный против декларативного] (https://ggorantala.dev/imperative-and-declarative-styles-of-programming)


Одной из мощных функций, которую команда Java включила в пакет JDK 1.8, является Streams API.


Целью потоков является обработка последовательности элементов путем выполнения различных операций над элементами.


Новый пакет Java для потоков — java.util.stream.


Что такое поток?


Давайте рассмотрим некоторые важные аспекты Streams API.


  1. Streams API используется для обработки коллекций объектов.

  1. Нет хранилища. Поток не является структурой данных, такой как массивы/стеки/очереди и т. д., вместо этого он принимает входные данные из коллекций, массивов или каналов ввода-вывода.

  1. Потоки не изменяют исходную структуру данных, они только предоставляют результаты в соответствии с конвейерными методами.

  1. Потоки используются для выполнения сложных операций обработки данных над данными коллекций. Они представляют конвейер, по которому будут проходить данные, и функции для работы с данными.

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

  1. Через любой поток может проходить неограниченное количество данных. Данные, полученные из потока, обрабатываются индивидуально по мере поступления.

  1. Функциональный характер. Операция над потоком производит результат, но не изменяет его источник. Например, фильтрация потока, полученного из коллекции, создает новый поток без отфильтрованных элементов, а не удаление элементов из исходной коллекции.

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

  1. Возможно неограниченный. В то время как коллекции имеют конечный размер, потоки в этом не нуждаются. Сокращающие операции, такие как limit(n) или findFirst(), могут позволить выполнять вычисления на бесконечных потоках за конечное время.

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

Создание потоков


У нас есть несколько разных способов создать поток.


  1. Из коллекций.

  1. Из массивов.

  1. Из произвольного количества объектов.

  1. Бесконечные и конечные потоки.

Преимущества


Ниже приведены преимущества использования Streams API.


  1. Мы уже видели разницу между императивным и декларативным подходами. С потоками мы переходим от императивного к декларативному программированию.

  1. Потоки можно применять только к коллекциям, таким как «список», «карта», «набор», «массивы» и т. д.

  1. Потоки поощряют меньшую изменчивость

  1. Они могут работать со своим содержимым параллельно, используя parallelStream().

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

Потоковый конвейер


Хватит говорить! Давайте посмотрим пример 🤩


Давайте посмотрим на пример, чтобы понять потоковый конвейер.


У нас есть список книг, и мы запускаем для него некоторую цепочку методов, таких как filter, map и т. д. Эта цепочка вызовов методов называется Stream Pipeline.


Это также называется функциональным программированием, поскольку мы передаем функции.


Book — это POJO с конструктором, геттерами и сеттерами.


```java


учебник {


Заголовок строки;


Автор строки;


Целый год;


Целочисленные копииSoldInMillions;


Двойной рейтинг;


Двойная стоимость в евро;


общедоступная книга (название строки, автор строки, целое число года, целое число копий, проданных в миллионах, двойная оценка, двойная стоимость в евро) {


это.название = название;


этот.автор = автор;


этот.год = год;


this.copiesSoldInMillions = копииSoldInMillions;


this.rating = рейтинг;


this.costInEuros = стоимостьInEuros;


публичная строка getAuthor () {


вернуть автора;


общественный двойной getRating () {


рейтинг возврата;


@Override


общедоступная строка toString () {


вернуть "Книга {" +


"название='" + название + '\'' +


", автор='" + автор + '\'' +


", год=" + год +


", копийПроданоВМиллионах=" + копийПроданоВМиллионах+


", рейтинг=" + рейтинг +


", стоимость в евро = " + стоимость в евро +


Еще один класс BookDatabase для фиктивной инъекции данных.


```java


импортировать java.util.Arrays;


импортировать java.util.List;


открытый класс BookDatabase {


общедоступный статический список<книга> getAllBooks() {


вернуть Arrays.asList(


новая Книга("Дон Кихот", "Мигель де Сервантес", 1605, 500, 3.9, 9.99),


новая книга («Повесть о двух городах», «Чарльз Диккенс», 1859, 200, 3.9, 10.0),


новая книга («Властелин колец», «Дж. Р. Р. Толкин», 2001, 150, 4.0, 12.50),


новая Книга("Маленький принц", "Антуан де Сент-Экзюпери", 2016, 142, 4.4, 5.0),


новая книга («Сон в Красной палате», «Цао Сюэцинь», 1791, 100, 4.2, 10.0)


И, наконец, класс BookApplication, который выполняет декларативное программирование или неизменность для каждого объекта книги.


```java


импортировать java.util.List;


открытый класс BookApplication {


public static void main(String[] args) {


List books = BookDatabase.getAllBooks();


книги.поток()


.filter(книга -> book.getRating() >= 4)


.map(Книга::getAuthor)


.forEach(System.out::println);


Выход:


```java


Дж.Р.Р. Толкин


Антуан де Сент-Экзюпери


Cao Xueqin


В приведенном выше примере у нас есть список объектов Book.


  1. Мы применили .stream(...) для преобразования списка объектов Book в поток объектов.

  1. Мы применили две промежуточные операции .filter(...), которые принимают Predicate и .map(...) для получения отфильтрованного потока объектов.

  1. Мы завершили его с помощью .forEach(...), чтобы напечатать все объекты.

Недостатки


  1. Если потоки не обрабатываются должным образом, они сильно влияют на производительность.

  1. Кривая обучения требует времени, так как есть много перегруженных методов, которые вам нужно изучить, что сбивает с толку, хотя это не недостаток, но я хочу оставить это здесь как недостаток.

  • Впервые опубликовано [здесь] (https://ggorantala.dev/introduction-to-java-streams-api)*


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE