Java 8 стала основным выпуском экосистемы Java. Из многих основных введенных функций потоки обеспечивают большую гибкость и удобство сопровождения. Вы можете рассматривать это как оператор SQL, представленный в другой форме в отдельной экосистеме, обеспечивающий больше функциональности. Будучи добавленным новым абстрактным слоем, он помогает нам применять функции к последовательностям объектов. Хотя есть много руководств, я попытался кратко объяснить это и помочь вам избежать трудностей, с которыми я столкнулся, привыкая к этому. Обратите внимание, что статья написана с учетом того, что вы уже говорите о работе с Lamda и функциональных интерфейсах.

На высоком уровне потоковые операции делятся на два типа: промежуточные операции и терминальные операции.

Промежуточные операции (также известные как отложенные операции):

Промежуточные операции — это те, которые совмещаются таким образом, чтобы помочь нам получить желаемый результат. Чтобы понять это простым способом, рассмотрите возможность использования приложения-калькулятора. Мы берем числа, оперируем ими, используя различные операции, такие как сложение, вычитание, умножение (например, 2+3*6). На языке потоков операции (+, *) можно рассматривать как промежуточные операции, а результат мы получаем с помощью оператора =, который можно рассматривать как терминальную операцию (эти математические операции приведены только для пояснения).

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

Хотя в этой статье мы не будем подробно обсуждать каждую из промежуточных операций, обзор некоторых операций должен помочь вам пройти этот этап. Наиболее широко используемыми операциями являются filter и map.

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

например .filter(s -> s.startsWith("c"))

Операция фильтра также позволяет использовать операторы И(&&), ИЛИ(||), НЕ(!).

Операция фильтра разделяет данные на основе логического значения, возвращаемого операцией, переданной в операции.

2. Map: функция map помогает нам преобразовать один тип объекта в другой. Он применяет предоставленную функцию ко всем предоставленным элементам. Возможно, вы захотите преобразовать строку в нижний регистр или возвести число в квадрат.

например .map(число -> число * число)

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

Другие типы промежуточных операций:

sorted(): сортирует элементы в естественном порядке.

Different(): возвращает поток уникальных элементов.

Вы можете найти больше промежуточных операций в следующей Документации Oracle (возврат должен быть типа Stream для промежуточных операций).

Примечание. Важно отметить, что промежуточные операции выполняются только после вызова терминальных операций, поэтому их также называют отложенными операциями.

Операции с терминалом:

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

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

Ниже приведены некоторые важные терминальные операции.

  1. Collect():метод collect помогает нам сохранять данные в нужном формате, таком как список, карта, строка и т. д. (существует два способавызвать метод collect которые являются встроенными и настраиваемыми, что достигается путем передачи дополнительных параметров, которые мы не будем обсуждать в этой статье из-за их сложности)

например .collect(Коллекторы.toList())

//Вышеприведенный оператор преобразует входные данные в список

2. Reduce().Метод сокращения помогает нам выполнять сокращение/накопление элементов (например, агрегирование) для получения желаемого результата. Он преобразует ввод в одно значение. (Есть три типа, с помощью которыхможет быть вызван метод-коллектор, который мы не будем обсуждать в этой статье из-за его сложности)

например .reduce(0,(результат, элемент) -> результат + элемент);

//Здесь начальное значение инициализируется равным 0, после чего каждый элемент добавляется, чтобы получить конечный элемент типа int.

3.forEach(): forEach используется для перебора каждого из элементов, что может использоваться для таких целей, как отображение элементов.

например .forEach(val -> System.out.println(val));

// Это печатает все элементы в потоке, перебирая их по одному.

Вы можете найти больше промежуточных операций в следующей Документации Oracle (возврат не должен быть типа Stream для терминальных операций).

Операции короткого замыкания:

Операции короткого замыкания останавливают выполнение текущего условия/этапа, как только данное условие удовлетворяется. Ниже приведены некоторые примеры операций короткого замыкания.

  1. limit(): ограничивает количество элементов, т.е. возвращает новый поток, как только выполняется условие ограничения.

//В качестве входных данных принимает длинный аргумент, а возвращаемый тип — поток

2. findAny(): возвращает один любой элемент из потока.

// Он не принимает никаких входных данных, а тип возвращаемого значения является необязательным

3. anyMatch(): возвращает логическое значение, если какой-либо элемент в потоке соответствует заданному предикату/функции.

// Он принимает предикат в качестве входных данных, а возвращаемый тип — логическое значение.

например логический результат = someCodeHere.anyMatch(s -> s.contains("привет"));

Есть много других операций короткого замыкания, которые можно найти в документации Oracle.

Рассмотрим пример кода ниже,

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

Не стесняйтесь использовать приведенный выше код на своем компьютере, чтобы тестировать, изменять и экспериментировать с кодом, что в дальнейшем поможет вам запачкать руки в коде.

Я надеюсь, что эта статья помогла вам разобраться с основами потоков Java 8. Если у вас есть какие-либо вопросы, не стесняйтесь комментировать их ниже.

Удачного дня:)