«Ах, черт!» Вот и мы снова ». Так я реагировал каждый раз, когда видел, как кто-то использует потоки вместо цикла.

Java 8 поставляется с множеством функций, наиболее популярными из которых являются лямбда-выражения и API потоков Java. Многие команды перешли на Java 8 только для того, чтобы воспользоваться сладкими ламдами. Однако я заметил, что я и многие другие используют Java 8 или выше, за исключением Streams API.
Попробуем разобраться в потоках.

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

Stream представляет собой последовательность объектов, полученных из источника, над которыми могут выполняться агрегированные операции.

Хорошо, а чем они отличаются от Коллекций?

Когда мы начинаем смотреть видео на Netflix или Youtube, сначала загружается небольшая часть видео, а затем воспроизводится. Нам не нужно загружать видео целиком, чтобы начать его просмотр. Это называется потоковой передачей. Эта аналогия помогает нам отличать Java Steams от Java Collections.

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

Существует поток для извлечения данных из источника, обработки и передачи данных в место назначения. Источником может быть коллекция, массив или ресурсы ввода-вывода.

Анатомия потока определяется как:

  1. Получить исходник (источник)
  2. Процесс (промежуточные операции)
  3. Получаем результат (терминальная работа)

Как получить стрим?

Что ж, вариантов довольно много

  1. Stream.of (значение1, значение2,….)
  2. List.stream ()
  3. Stream.of (arrayOfElements)
  4. Строковые символы или Строковые токены

Потоковые операции

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

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

Промежуточные операции

  1. 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 (), если это необходимо.

Ресурсы