Рубрики
Без рубрики

Потоки Java и Фибоначчи

Таким образом, многие люди в настоящее время все еще пытаются понять подобные выражения в Java 8+: S… Помеченный java, фибоначчи, потоки, код.

Таким образом, многие люди в настоящее время все еще пытаются понять подобные выражения в Java 8+:

Stream.iterate(new long[]{ 0L, 1L }, p->new long[]{ p[1], p[0]+p[1] }).map(p -> p[0]).limit(10).map(p->p+" ").forEach(System.out::print);

Итак, скажите мне, как, у вас есть представление о том, что будет делать эта строка, когда вы нажмете “Бежать”? Да, вы правы, у вас на консоли будет напечатана последовательность Фибоначчи из 10 элементов, вот так:

0 1 1 2 3 5 8 13 21 34

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

Итак, ваш второй шанс прямо здесь:

Arrays.asList(1, 2, 2, 3, 4, 4, 4, 5, 6, 8).stream()
    .distinct()
    .filter(x -> x % 2 == 0)
    .map(x -> x * 10)
    .skip(1)
    .limit(2)
    .peek(System.out::println)
    .reduce(0, Integer::sum)

Сейчас мне не нужна математика, потому что я хотел показать вам, как это работает шаг за шагом.

Итак, прежде всего, что, черт возьми, такое ПОТОК ?

То, что вы должны иметь в виду, это:

  • Потоки не являются структурой данных
  • Потоки не хранят и не изменяют данные
  • Его можно определить как оболочку вокруг источника данных
  • Поддерживает операции в функциональном стиле
  • Быстрая и удобная массовая обработка через источник данных
  • Итерации по элементам являются последовательными и декларативными
  • Параллельный, неизменяемый и потокобезопасный
  • Ленивая оценка
  • Одноразовое использование
  • Не путайте с вводом-выводом Java (напр. Поток ввода файла)

Кроме того, у нас есть:

  • Промежуточные операции: операции с цепочкой потоков, возвращающие новые потоки (конвейер)
  • Терминальные операции: выполнение потока и создание непотокового объекта (результата)

Вы можете создать поток, вызвав методы stream() или параллельный поток() , или даже использовать Stream.of , Поток.обнуляемого или или

Итак, давайте попробуем немного вернуться назад и “отладить” простой пример там:

Arrays.asList(1, 2, 2, 3, 4, 4, 4, 5, 6, 8)

Создает новую коллекцию, чтобы мы могли перебирать ее элементы с помощью потока

.stream()

Запускает новый поток

.distinct()

Сохранять отдельные элементы, возвращая: [1, 2, 3, 4, 5, 6, 8]

.filter(x -> x % 2 == 0)

Фильтруйте парные элементы, применяя мод 2, возвращая: [2, 4, 6, 8]

.map(x -> x * 10)

Умножает каждый отфильтрованный элемент на 10, возвращая: [20, 40, 60, 80]

.skip(1)

Пропускает первый элемент последовательности, возвращая: [40, 60, 80]

.limit(2)

Возвращает первые 2 элемента последовательности: [40, 60] Это команда “короткого замыкания”, т.е. она прерывает обработку потока, когда условие совпадает – в данном случае, когда мы достигаем второго элемента

.peek(System.out::println)

Своего рода “отладочный” режим потока, в этом случае он будет печатать каждый оставшийся элемент операции потока: 40 и 60

.reduce(0, Integer::sum)

В этом случае мы собираемся эффективно использовать поток и получить от него целочисленный результат: сумму всех элементов, где 0 является начальным значением, и Integer::sum вызывает функцию Integer.sum(int a, int b) из класса Integer, которая будет выполняться над каждым оставшимся элементом из операции потока, то есть 40 и 60, затем в результате 100 .

А теперь, как насчет того, что там с Фибоначчи, чувак? Ладно, давайте вернемся к этому.

Stream.iterate

По определению, у нас есть:

Возвращает бесконечный последовательный упорядоченный поток, созданный итеративным применением функции f к начальному элементу seed, создавая поток, состоящий из seed, f(seed), f(f(seed)) и т. Д.

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

new long[]{ 0L, 1L } // as the 1st parameter

Для “кикстарта” Фибоначчи нам понадобятся два элемента: 0 и 1 . Затем сумма обоих даст следующий элемент и так далее (вы это знаете, верно?). Тем не менее, этот массив будет представлять пару первых значений последовательности Фибоначчи в качестве первого элемента потока.

p->new long[]{ p[1], p[0]+p[1] }) // as the 2nd parameter

Таким образом, этот объект p создаст новый массив, содержащий два элемента:

  • p[1] : какой массив является предыдущим в позиции 1;
  • p[0] + p[1] : какой массив является предыдущим в позиции 0 плюс его позиция 1;
.map(p -> p[0])

Дело в том, что до сих пор у нас продолжается поток парных элементов, однако наша главная цель – напечатать элементы этой последовательности, верно? Итак, теперь, чтобы получить “текущий” элемент этой операции, “сопоставив” текущую пару значений этого потока одному элементу, в данном случае массиву в позиции 0 .

.limit(10)

Это важно, как было сказано ранее, это Вернет бесконечный последовательный упорядоченный поток по умолчанию. Итак, чтобы это не продолжалось вечно, когда ваш компьютер сгорает, мы определяем “ограничение” для этой операции, обрабатывая только первые 10 элементов.

.map(p->p+" ")

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

.forEach(System.out::print)

forEach также является терминальной операцией, и она будет выполнять итерацию по результирующей коллекции потока. Итак, здесь мы просто печатаем текущий элемент с помощью хорошо известного System.out.print .

Если вы не знакомы с подобными выражениями System.out::печать тем не менее, лучше ознакомьтесь со ссылкой на метод, которая представляет собой особый тип лямбда-выражения, очень полезного для уменьшения шаблонности и улучшения читабельности. Возможно, я расскажу об этом подробнее позже, написав о функциональном программировании Java, так что следите за обновлениями!

Оригинал: “https://dev.to/bzani/java-streams-and-fibonacci-2p9l”