«Ах, черт!» Вот и мы снова ». Так я реагировал каждый раз, когда видел, как кто-то использует потоки вместо цикла.
Java 8 поставляется с множеством функций, наиболее популярными из которых являются лямбда-выражения и API потоков Java. Многие команды перешли на Java 8 только для того, чтобы воспользоваться сладкими ламдами. Однако я заметил, что я и многие другие используют Java 8 или выше, за исключением Streams API.
Попробуем разобраться в потоках.
Что такое потоки?
Stream представляет собой последовательность объектов, полученных из источника, над которыми могут выполняться агрегированные операции.
Хорошо, а чем они отличаются от Коллекций?
Когда мы начинаем смотреть видео на Netflix или Youtube, сначала загружается небольшая часть видео, а затем воспроизводится. Нам не нужно загружать видео целиком, чтобы начать его просмотр. Это называется потоковой передачей. Эта аналогия помогает нам отличать Java Steams от Java Collections.
Коллекции - это структуры данных в памяти. Каждый элемент необходимо вычислить, прежде чем он будет добавлен в коллекцию. поток - это фиксированная структура данных, в которой элементы вычисляются по запросу.
Существует поток для извлечения данных из источника, обработки и передачи данных в место назначения. Источником может быть коллекция, массив или ресурсы ввода-вывода.
Анатомия потока определяется как:
- Получить исходник (источник)
- Процесс (промежуточные операции)
- Получаем результат (терминальная работа)
Как получить стрим?
Что ж, вариантов довольно много
- Stream.of (значение1, значение2,….)
- List.stream ()
- Stream.of (arrayOfElements)
- Строковые символы или Строковые токены
Потоковые операции
- Промежуточные операции - это операции, которые преобразуют или фильтруют данные в потоке. Промежуточные операции всегда возвращают новый поток.
- Терминальные операции - это операции, возвращающие одно значение.
Давайте заранее создадим коллекцию, чтобы увидеть, как ведут себя операции.
Промежуточные операции
- Stream.filter ()
.stream () получает поток из источника (список номеров).
.filter () предоставляется с условием для фильтрации всех строк, длина которых больше чем 3.
Являясь промежуточной операцией, это позволяет нам вызывать другую потоковую операцию (forEach в этом примере)
.forEach () также промежуточная операция и вызывает функцию печати для каждого элемента в потоке.
Вывод:
три
четыре
пять
2. Stream.map ()
.map () преобразует каждый элемент в другой объект с помощью данной функции.
В этом примере он преобразует каждую строку в ее строку в верхнем регистре.
Вывод:
ТРИ
ЧЕТЫРЕ
ПЯТЬ
3. Stream.sorted ()
.sorted () создает отсортированный поток. Но он не сортирует список номеров.
Вывод:
ПЯТЬ
ЧЕТЫРЕ
ТРИ
Терминальные операции
Терминальные операции возвращают значение вместо потока.
1. Stream.forEach ()
.forEach () выполняет итерацию по всем элементам потока и выполняет определенную операцию над каждым из них. Операция передается функции как параметр.
Вывод:
три
четыре
пять
2. Stream.collect ()
Метод .collect () - это терминальная операция, которая запускает внутреннюю итерацию элементов и собирает элементы в потоке в коллекцию или объект любого типа данных.
Вывод:
[ONE, TWO, THREE, FOUR, FIVE]
3. Stream.match ()
Вывод:
true
false
false
Обратитесь к документации для получения дополнительных потоковых операций.
Режимы потоков
Режим выполнения - это свойство потока. Потоки создаются с первоначальным выбором последовательного или параллельного выполнения.
Collection.stream () создает последовательный поток, а Collection.parallelStream () создает параллельный транслировать.
Давайте разберемся с этим на примере.
Давайте создадим список целых чисел.
Вывод:
Список ввода = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Вывод:
Thread = main
Thread = main
Thread = main
Thread = main
Thread = main
Последовательный поток = [0, 2, 4, 6, 8]
Вывод:
Thread = main
Thread = ForkJoinPool.commonPool-worker-19
Thread = ForkJoinPool.commonPool-worker-27
Thread = ForkJoinPool. commonPool-worker-5
Thread = ForkJoinPool.commonPool-worker-9
Parallel Stream = [6, 2, 0, 8, 4]
Метод BaseStream.isParallel () используется для проверки того, должна ли выполняться операция терминала, будет ли она выполняться параллельно?
Вывод:
- это serialStream Parallel: false
- parallelStream Parallel: true
Позже потоки можно преобразовать в последовательный режим с помощью sequence () или в параллельный режим с помощью методов parallel (), если это необходимо.