В этой статье мы поговорим о API-интерфейсе Stream, добавленном в Java 8, и о том, как он изменил способ работы программ на Java. Это добавило аккуратности, а также сделало код более читабельным. Это помогает проводить функциональное программирование на Java. Итак, без лишних слов, давайте узнаем больше об этом драгоценном камне Java!
Вам также может понравиться:
Ваше руководство по потокам Java [Учебники и статьи]
Что такое Stream API?
Stream API, включенный в Java 8, используется для обработки collections of Objects. Это поток объектов, на котором в конвейере применяются различные методы для получения результата. Проще говоря, он проходит через данные Collection<Object>и применяет различные методы Objectдля объединения их в желаемый результат, не влияя на оригинал Object.
Что обеспечивает поток
Stream ничего не хранит; вместо этого он работает с данным Collection, Arrayили вводом / выводом (да, вы можете использовать его для ввода / вывода). Не изменяя исходные данные, он применяет методы к данным. Ленивая оценка помогает добавить несколько intermediate operationsбез запуска полного потока. Оценивается только после добавления terminal operation. это добавляет аккуратность и делает коды чище. Создайте более полный код. И многое другое
Что нужно знать, прежде чем идти
Stream позволяет практиковать функциональное программирование на Java. Это означает, что вам должно быть удобно с функциональными интерфейсами и лямбда-выражениями. Если вы хорошо понимаете эти концепции, никто не сможет помешать вам понять API-интерфейс Stream. Вы можете найти примеры кода на GitHub или просмотреть полный проект здесь .
Как стримить
Потоки могут быть реализованы несколькими способами. Несколько фокусов:
- Коллекции stream()иparallelStream()методы
- С помощью Arrays.stream(Object[])
- Статические фабричные методы записи потока , такие как Stream.of(Object[]),IntStream.range(int, int)илиStream.iterate(Object, UnaryOperator)
- Потоковая строка файла BufferedReader.lines()
- Потоки случайных чисел могут быть получены из Random.ints().
Первая и вторая пули — это то, что мы используем чаще всего. Для нашего обсуждения мы будем придерживаться Collection#steam()метода. Например:
Джава
1
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5,
2
       6, 7, 8, 9, 10);
3
//start the stream
4
list.stream()
5
        // multiplying each number by 2
6
        .map(n -> n * 2)
7
        //taking forward only even numbers
8
        .filter(n -> n % 2 == 0)
9
        //printing each even number
10
        .forEach(n -> System.out.println(n));
Операции с потоковым конвейером
Мы можем выполнить две операции над конвейером Stream:
- Промежуточная операция
- Терминальная операция
Промежуточная операция преобразует или фильтрует объект в предыдущем конвейере. Эти методы — не что иное, как Functional Interfacesмы упоминали ранее. Вы должны ознакомиться с ними, чтобы легко понять эту операцию без каких-либо проблем.
Stream не будет выполнять промежуточные операции, пока не будет вызвана терминальная операция . Это указание потоку запустить конвейер. Как только мы вызываем операцию терминала, конвейер заканчивается, и он возвращает желаемый результат. После работы терминала мы не можем использовать промежуточные операции, так как конвейер закончился. Он может быть вызван только один раз в конце конвейера. Однако вы можете снова запустить поток, если терминальная операция возвращает коллекцию — что я категорически против. Вы можете в значительной степени делать все внутри одного потока.
Промежуточные операции
В конвейере Stream у нас может быть несколько промежуточных операций, которые преобразуют или фильтруют данные, которые будут поступать в следующий канал, не влияя на фактические данные в Коллекции. Эти операции возвращают поток желаемого результата вместо фактического результата, через который мы можем добавить более промежуточную операцию, не нарушая конвейер потока. Мы будем говорить об этом mapи filterв этом посте, и в другой статье. Методы  mapи filterте, которые вам понадобятся в большинстве случаев.
Эти методы применяются один за другим к элементам конвейера, а не ко всем сразу.
отображение (функция)
Думайте о map(Function)функции преобразования, которая преобразует данный объект в другой. Он принимает a Functionв качестве параметра, который принимает элемент в потоке в качестве входных данных, выполняет некоторую операцию, которую мы ему сообщаем, и возвращает Stream результирующего объекта. Если мы посмотрим на наш предыдущий пример, он умножает каждое число на 2. У нас может быть другая карта, которая может добавить 2 к числу, а затем еще одну карту, чтобы преобразовать ее в другой объект, а затем еще один, и так далее — вы получите идея.
Джава
xxxxxxxxxx
1
list.stream()
2
        // 1. multiplying each number by 2
3
        .map(n -> n * 2)
4
        // 2. Converting to string.
5
        .map(n -> "CodersTea.com-Post No : " + n)
6
        //3. Now you will be working on the
7
        //stream of String
8
        //4. we add another string to the previous
9
        .map(string -> string + ". Another String")
10
        //print the end result
11
        .forEach(System.out::println);
В приведенном выше примере посмотрите, как мы преобразовали список Integerв String. Давайте разберемся с этим:
- Умножая каждое число на 2. Итак, 1 становится 2, 2 становится 4 и так далее.
- Мы прикрепили номер к строке, результатом которой стал объект String.
- Предыдущая карта сделала Stream<Integer>toStream<String>из-за возвращаемого типа строки.
- Мы снова прикрепили еще одну строку для выполнения какой-либо операции.
- Наконец печать результатов, которая выглядит следующим образом:
Вывод:
Джава
x
1
CodersTea.com-Post No : 2. Another String
2
CodersTea.com-Post No : 4. Another String
3
CodersTea.com-Post No : 6. Another String
4
CodersTea.com-Post No : 8. Another String
5
CodersTea.com-Post No : 10. Another String
6
CodersTea.com-Post No : 12. Another String
7
CodersTea.com-Post No : 14. Another String
8
CodersTea.com-Post No : 16. Another String
9
CodersTea.com-Post No : 18. Another String
10
CodersTea.com-Post No : 20. Another String
фильтр (предикат)
Фильтр, как следует из названия, фильтрует элементы до того, как достигнет следующей трубы. Проще говоря, если элемент удовлетворяет условию, он позволяет ему пройти; в противном случае он не позволит выполнить следующую операцию. Это принимает Predicateв качестве параметра.
Джава
xxxxxxxxxx
1
long count = list.stream()
2
        // 1. Need only even numbers
3
        .filter(n -> n % 2 == 0)
4
        // 2. Checking if the Number is
5
        // greater than 5
6
        .filter(n -> n > 5)
7
        //3. multiplying the number by 5
8
        // just to show how we can use multiple
9
        // Intermediate operation together
10
        .map(n -> n * 5)
11
        // 4. Any number less than 50
12
        .filter(n -> n < 50)
13
        // Counting how much elements
14
        // survived teh pipeline
15
        .count();
16
System.out.println("Total " + count + " numbers survived the storm");
Так много фильтров. Хорошо, давайте разберемся с этим, не так ли?
- Возьмите только четные числа впереди.
- Вперед только номера больше 5
- Умножьте число на 5. Опять же, просто чтобы показать, что вы можете иметь несколько промежуточных операций в одном потоке.
- Разрешить числа, которые меньше 50.
- Наконец, count(Terminal Operation) сколько выжило после такой большой фильтрации.
Вывод:
Джава
xxxxxxxxxx
1
Total 2 numbers survived the storm
Терминальная операция
До сих пор мы видели, как операции выполняют что-то в конвейере и возвращают поток. В итоге нам понадобится конечный результат. Здесь начинается работа терминала. Он не только дает нам желаемый результат, но и запускает Stream. Как я уже сказал, стрим ленив; он ничего не будет делать, независимо от того, сколько промежуточных операций мы добавляем в конвейер, если он не видит своего завершения, терминальной операции.
Вы не можете использовать тот же поток после того, как он был закрыт операцией терминала. В противном случае, это бросит
IllegalStateException: stream has already been operated upon or closed. Вы должны начать новый поток
 
  
  
 Терминальными операциями, которые мы использовали в приведенных выше примерах, являются forEachи count. Давайте рассмотрим их и несколько других ниже.
Foreach (Consumer)
forEach(Consumer)принимает входные данные, но не возвращает выходные данные, принимая  Consumerв качестве параметра. Используйте это, если хотите что-то сделать, не возвращая ничего. Мы использовали его для печати номеров.
Джава
xxxxxxxxxx
1
list.stream()
2
        // square of each number
3
        .map(n -> n * n )
4
        .forEach(n -> System.out.print(" "+ n));
5
        //output: 
6
        // 1 4 9 16 25 36 49 64 81 100
кол-()
Как следует из названия, он используется для подсчета элементов, достигнутых до конца. Как в нашем примере фильтра, подсчет, кто выполнил все условия фильтра.
Джава
xxxxxxxxxx
1
list.stream()
2
        // even numbers less than 5s
3
        .filter(n -> n < 5 && n %2 == 0)
4
        .count(); // returns 2
собирать ()
Я использую это чаще, чем любая другая терминальная операция. Позволяет создавать Collectionиз элементов потока после их обработки. Это Collectionможет быть List, Setили Map. Коллекция включает элементы, прошедшие через последнюю трубу.
Джава
xxxxxxxxxx
1
List<Integer> processedList = list.stream()
2
        // multiplying by 5
3
        .map(n -> n * 5)
4
        // numbers less than 30
5
        .filter(n -> n < 30)
6
        //add  +2
7
        .map(n -> n + 2)
8
        // give the list of processed numbers
9
        .collect(Collectors.toList());
10
System.out.println("processed List is \n " + processedList);
В конвейере мы умножили число на 5, затем отфильтровали числа меньше 30 и добавили 2. И после того, как все элементы завершат обработку, мы собираем их в список.
Джава
xxxxxxxxxx
1
processed List is
2
 [7, 12, 17, 22, 27]
 
  
  
 
 
  Заключение
Мы изучили, что такое Stream API, как его получить и как его лучше всего использовать. Этот пост похож на вводный пост для Stream API. В шахте так много алмазов, которые мы будем добывать в следующем посте.
Вы можете найти исходный код на GitHub или полный проект здесь .
Дальнейшее чтение
Ваше руководство по потокам Java [Учебники и статьи]
Обзор расширений API Java Stream
Что в имени: Соглашения об именах Java
Стать мастером серии Java Streams: часть 1 , 2 , 3 , 4 , 5 и 6