Java 8 стала основным выпуском экосистемы Java. Из многих основных введенных функций потоки обеспечивают большую гибкость и удобство сопровождения. Вы можете рассматривать это как оператор SQL, представленный в другой форме в отдельной экосистеме, обеспечивающий больше функциональности. Будучи добавленным новым абстрактным слоем, он помогает нам применять функции к последовательностям объектов. Хотя есть много руководств, я попытался кратко объяснить это и помочь вам избежать трудностей, с которыми я столкнулся, привыкая к этому. Обратите внимание, что статья написана с учетом того, что вы уже говорите о работе с Lamda и функциональных интерфейсах.
На высоком уровне потоковые операции делятся на два типа: промежуточные операции и терминальные операции.
Промежуточные операции (также известные как отложенные операции):
Промежуточные операции — это те, которые совмещаются таким образом, чтобы помочь нам получить желаемый результат. Чтобы понять это простым способом, рассмотрите возможность использования приложения-калькулятора. Мы берем числа, оперируем ими, используя различные операции, такие как сложение, вычитание, умножение (например, 2+3*6). На языке потоков операции (+, *) можно рассматривать как промежуточные операции, а результат мы получаем с помощью оператора =, который можно рассматривать как терминальную операцию (эти математические операции приведены только для пояснения).
Промежуточные операции помогают нам создать конвейер операций, преобразуя один поток в другой. Промежуточные операции возвращают поток нового типа, который может быть дополнительно обработан другими операциями.
Хотя в этой статье мы не будем подробно обсуждать каждую из промежуточных операций, обзор некоторых операций должен помочь вам пройти этот этап. Наиболее широко используемыми операциями являются filter и map.
- Фильтр: как следует из названия, помогает нам отфильтровывать то, что больше не требуется для обработки. Простым примером операции фильтра может быть случай, когда вам требуется строка, начинающаяся с буквы «с».
например .filter(s -> s.startsWith("c"))
Операция фильтра также позволяет использовать операторы И(&&), ИЛИ(||), НЕ(!).
Операция фильтра разделяет данные на основе логического значения, возвращаемого операцией, переданной в операции.
2. Map: функция map помогает нам преобразовать один тип объекта в другой. Он применяет предоставленную функцию ко всем предоставленным элементам. Возможно, вы захотите преобразовать строку в нижний регистр или возвести число в квадрат.
например .map(число -> число * число)
Операция карты принимает значение и преобразует его в значение на основе предоставленной функции. Карта возвращает поток, который может быть дополнительно обработан другими операциями.
Другие типы промежуточных операций:
sorted(): сортирует элементы в естественном порядке.
Different(): возвращает поток уникальных элементов.
Вы можете найти больше промежуточных операций в следующей Документации Oracle (возврат должен быть типа Stream для промежуточных операций).
Примечание. Важно отметить, что промежуточные операции выполняются только после вызова терминальных операций, поэтому их также называют отложенными операциями.
Операции с терминалом:
Терминальные операции — это те, которые выполняются, но не создают взамен поток. Все промежуточные операции, сложенные в стек, выполняются при выполнении терминальных операций.
Терминальные операции действуют как триггер, который выполняет все промежуточные операции, которые помогают нам получить желаемые результаты.
Ниже приведены некоторые важные терминальные операции.
- Collect():метод collect помогает нам сохранять данные в нужном формате, таком как список, карта, строка и т. д. (существует два способавызвать метод collect которые являются встроенными и настраиваемыми, что достигается путем передачи дополнительных параметров, которые мы не будем обсуждать в этой статье из-за их сложности)
например .collect(Коллекторы.toList())
//Вышеприведенный оператор преобразует входные данные в список
2. Reduce().Метод сокращения помогает нам выполнять сокращение/накопление элементов (например, агрегирование) для получения желаемого результата. Он преобразует ввод в одно значение. (Есть три типа, с помощью которыхможет быть вызван метод-коллектор, который мы не будем обсуждать в этой статье из-за его сложности)
например .reduce(0,(результат, элемент) -> результат + элемент);
//Здесь начальное значение инициализируется равным 0, после чего каждый элемент добавляется, чтобы получить конечный элемент типа int.
3.forEach(): forEach используется для перебора каждого из элементов, что может использоваться для таких целей, как отображение элементов.
например .forEach(val -> System.out.println(val));
// Это печатает все элементы в потоке, перебирая их по одному.
Вы можете найти больше промежуточных операций в следующей Документации Oracle (возврат не должен быть типа Stream для терминальных операций).
Операции короткого замыкания:
Операции короткого замыкания останавливают выполнение текущего условия/этапа, как только данное условие удовлетворяется. Ниже приведены некоторые примеры операций короткого замыкания.
- limit(): ограничивает количество элементов, т.е. возвращает новый поток, как только выполняется условие ограничения.
//В качестве входных данных принимает длинный аргумент, а возвращаемый тип — поток
2. findAny(): возвращает один любой элемент из потока.
// Он не принимает никаких входных данных, а тип возвращаемого значения является необязательным
3. anyMatch(): возвращает логическое значение, если какой-либо элемент в потоке соответствует заданному предикату/функции.
// Он принимает предикат в качестве входных данных, а возвращаемый тип — логическое значение.
например логический результат = someCodeHere.anyMatch(s -> s.contains("привет"));
Есть много других операций короткого замыкания, которые можно найти в документации Oracle.
Рассмотрим пример кода ниже,
Приведенный выше код представляет собой немного сложный поток (это поможет вам проанализировать использование каждой из функций), объясненный построчно, который состоит из промежуточных, терминальных, а также операций короткого замыкания. Поток помогает нам получить N самых часто встречающихся элементов из входного массива, а результаты возвращаются в виде массива типа int.
Не стесняйтесь использовать приведенный выше код на своем компьютере, чтобы тестировать, изменять и экспериментировать с кодом, что в дальнейшем поможет вам запачкать руки в коде.
Я надеюсь, что эта статья помогла вам разобраться с основами потоков Java 8. Если у вас есть какие-либо вопросы, не стесняйтесь комментировать их ниже.
Удачного дня:)