Вы отправили слишком много запросов, поэтому ваш компьютер был заблокирован.
Для того, чтобы предотвратить автоматическое считывание информации с нашего сервиса, на Linguee допустимо лишь ограниченное количество запросов на каждого пользователя.
Пользователям, браузер которых поддерживает Javascript, доступно большее количество запросов, в отличие от пользователей, чей браузер не поддерживает Javascript. Попробуйте активировать Javascript в настройках вашего браузера, подождать несколько часов и снова воспользоваться нашим сервером.
Если же ваш компьютер является частью сети компьютеров, в которой большое количество пользователей одновременно пользуется Linguee,сообщитеоб этом нам.
Стрим — что это такое? Определение, значение, перевод

Привет, братэлло! Стрим это «поток» в синхронном переводе с английского. Но не тот, который быстрый горный кавказский рек, да? А тот, который медленный и всё время тормозит этот проклятый ютюб, понимаешь?
Как вы уже догадались, стримом в русском языке называют поток данных по интернету, позволяющий смотреть видео или слушать музыку в режиме онлайн. Стримы активно используются в индустрии интернет-радио, а также в различных подкастах, вебинарах и прочей бесполезной сетевой активности.
Кстати, в английском языке слово «stream» может означать и обычный ручеёк, но это уже совсем другая история. Надеюсь, малыш, что тебе понравилось выученное тобой сегодня словцо. До новых встреч в бурных потоках интернет-трафика.
Метки / Интернет
Понравилась страница?
Пожалуйста, поделитесь ссылкой с друзьями:
Стрим
В Unisender есть все для рассылок: можно создавать и отправлять клиентам письма и SMS, настроить чат-бота и делать рассылки в Telegram и даже собрать простой лендинг для пополнения базы контактов.
Стрим (англ. stream, поток) — это видео в интернете, которое пользователь (стример) транслирует аудитории в режиме реального времени. Стример выходит в прямой эфир в соцсетях или на специальных сайтах — стриминговых площадках.
В отличие от обычных видеоблогеров, которые также иногда проводят онлайн-трансляции, стримеры никогда не монтируют свои ролики заранее. Они напрямую общаются с подписчиками и позволяют им наблюдать за своими действиями в режиме реального времени.
Популярность стриминга в интернете растет. По данным компании DonationAlerts , только за пандемийный 2020 год количество стримеров выросло на 33%, и продолжает увеличиваться.
Основные стриминговые направления
Стрим зародился в сегменте видеоигр и киберспорта. Геймеры транслировали происходящее у них на мониторе и комментировали ход игры, при этом зрители могли подключиться к обсуждению в специальном чате.
Так появилось самое популярное стриминговое направление — игровое . Интернет-трансляции с мировых соревнований по киберспорту или мастерское прохождение сложных уровней Dota 2 привлекают тысячи, а иногда и миллионы зрителей.
Постепенно стриминг набрал популярность за пределами игровой среды. Стримы снимают кулинары, спортсмены, бьюти-блогеры, путешественники, медийные личности, посетители мероприятий и наблюдатели уникальных природных явлений.
В формате stream можно снимать интервью, обучающие ролики и просто общаться с подписчиками на разные темы. Все эти виды трансляций относятся к лайфстайл-направлению.

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

Корпорация «Роскосмос» стримит запуски своих космических кораблей на своем YouTube-канале. Наблюдать за редким и эффектным зрелищем могут миллионы зрителей. Источник
Персональные стримы могут не иметь привязки к какому-либо жанру, событию или тематике. Главный интерес для подписчиков представляет личность стримера и общение с ним. Чаще всего персональные IRL-стримы (англ. in real life) снимают медийные личности или уже раскрученные блогеры с широкой постоянной аудиторией.
Популярные площадки для стрима
На основе исследования компании DonationAlerts за 2021 год рассмотрим самые популярные в России площадки для стрима.

You Tube
Видеохостинг YouTube — самая популярная стриминговая площадка в России. Большинство российских стримеров используют YouTube Live в качестве основной платформы для своих эфиров.
YouTube дает доступ к широкой аудитории и не ставит ограничений по тематике контента при соблюдении правил площадки . Начать прямую трансляцию можно с зарегистрированного канала, подлинность которого подтверждена модераторами сайта.
Twitch
Главный мировой стриминговый сервис, тематика эфиров преимущественно игровая. Основной контент сайта — персональные game-трансляции стримеров, онлайн-трансляции соревнований по киберспорту, новости игровой индустрии.
Twitch предоставляет возможность стать стримером каждому, кто зарегистрируется как автор канала и даст согласие соблюдать правила платформы . Сразу после регистрации стример может начать трансляцию, открыть чат для зрителей и фолловеров, использовать инструменты аналитики.

На страницу самого популярного стримера в мире подписаны более 18 млн человек. Ninja стримит в Twitch с 2011 года. Источник
Социальные сети
Стримеры используют социальные сети как основные или дополнительные площадки. Функция Live для выхода в прямой эфир есть почти во всех крупных социальных сетях. Трансляции можно вести в режиме реального времени и сохранять их записи у себя на странице.
С марта 2022 года в России стримить и зарабатывать на этом по-прежнему можно в « Одноклассниках » и « ВКонтакте ».
Ряд иностранных социальных сетей, ранее активно освоенных российскими стримерами (Facebook*, Instagram*, Twitter), пока заблокированы на территории РФ, так как признаны экстремистскими. Китайский TikTok временно ограничил для российских пользователей возможность вести прямые трансляции из-за так называемого « закона о фейках ».
Способы заработка стримеров
Чтобы трансляции приносили деньги, нужно привлечь большую аудиторию и регулярно выходить в прямые эфиры. Стриминговые сервисы предоставляют пользователям разные варианты монетизации контента. Перечислим основные способы заработка стримеров в интернете.
Донаты (англ. donation, пожертвование) — добровольные денежные переводы стримеру от аудитории. Донаты могут быть любого размера и формируют существенную долю заработка популярных стримеров.
Зрители перечисляют деньги прямо во время трансляции через специальные сервисы для приема донатов либо в любое другое время по платежным реквизитам. Таким образом пользователи могут выразить благодарность стримеру за интересные эфиры, поддержать материально его проект или помочь достигнуть какой-либо цели.
Партнерские программы стриминговых площадок предполагают размещение коммерческой рекламы во время трансляций стримеров. Рекламодатели готовы платить сайту за доступ к аудитории популярных стримеров, а сайты готовы делиться со стримерами прибылью от рекламы.
Участвовать в партнерских программах могут стримеры, чьи каналы и трансляции соответствуют требованиям площадок. Например, Twitch разработал для каждого пользователя страницу достижений , которая ведет к заявке на партнерство.

Чтобы стать партнером Twitch, нужно не только выполнить все основные условия площадки со страницы достижений, но и понравиться модераторам Источник
Платные подписки на канал стримера открывают для зрителей дополнительные возможности. Например, просмотр эфиров без рекламы, выделенный ник в общем чате или участие в отдельном чате для платных подписчиков, расширенный набор смайлов, доступ к скрытому контенту и т.п.
Как правило, возможность подключить платные подписки дают стриминговые площадки в рамках партнерской программы. С социальными сетями сложнее: далеко не в каждой из них встроена эта функция.
Реклама во время трансляций. Стримеры с большой аудиторией могут зарабатывать на размещении рекламы напрямую от рекламодателей, без посредничества стриминговой площадки. В этом случае всю прибыль от рекламы они забирают себе.
Зачем нужен стриминг в бизнесе
Многие мировые бренды используют стриминг для продвижения в интернете. Список компаний не ограничивается цифровой и игровой индустрией. Стримы в рекламных целях используют Burberry, «Газпромбанк», L’Oreal, Nike, «Додо Пицца» и даже политики во время предвыборных кампаний.

С 2017 года на азиатском рынке получил распространение новый вид онлайн-продвижения — live commerce. Стримеры и медийные личности в прямом эфире рассказывают о товаре, а зрители могут купить его прямо во время трансляции. Сейчас тренд набирает популярность на маркетплейсах во всем мире. Например, стримы продавцов с конца 2020 года запускает российский Ozon в разделе Ozon Live. Источник
Интегрировать рекламу или PR-материалы в стримы полезно, чтобы повысить узнаваемость бренда, привлечь клиентов, анонсировать новый продукт или увеличить продажи. Стоит помнить, что это относительно новый способ продвижения, в котором есть как плюсы, так и минусы.
Наблюдение за стримами — процесс очень залипательный. Часто это что-то неважное, не требующее концентрации зрителя, идущее « белым шумом » . В прямом эфире люди едят, снимают ASMR, показывают покупки, красятся, болтают о повседневной жизни, на бытовом уровне обсуждают новости и сплетни.
В рамках таких расслабляющих и отвлекающих стримов можно привлекать внимание к своему продукту. Например, ASMR-блогер может использовать ваш продукт в качестве триггера и шепотом рассказать про его достоинства. Те, кто привлекают людей обсуждениями, шутками и харизмой, могут в своей же шуточной манере рассказывать о товаре. Здесь важны нативность и гибкость. В стриминге много странных форматов, но если вы сможете в них органично встроиться, такая реклама понравится пользователям.
Head of SMM в сервисе автопостинга SMMplanner
Аудитория стриминговых площадок преимущественно молода, платежеспособна, настроена на развлечения, доверительно относится к рекомендациям любимых стримеров и открыта новому.
Вместе с тем, восприятие аудитории стримов может значительно отличаться от привычных реакций аудитории блогеров из соцсетей. Реакция зрителей стримов менее предсказуема. Сообщество геймеров — специфичная аудитория со своими правилами и представлениями.
Неправильно выбранный формат и способ подачи контента может вызвать токсичную реакцию в чате зрителей прямо во время эфира. Нейтрализовать поток негатива в таких условиях сложно или почти невозможно, поэтому выбирать стримеров и формат рекламы нужно очень аккуратно.
Стримы в маркетинговую стратегию пока включают немногие российские компании, а значит, это хорошая возможность обойти конкурентов и освоить новые сегменты клиентов. Но, экспериментируя со стримами в первый раз, не стоит вкладывать в рекламу у стримеров значительную часть рекламного бюджета.
Выбор способа использования стримов как маркетингового инструмента зависит от типа продукта, целей рекламной кампании и от рекламного бюджета.
Как использовать стримы в маркетинге: способы и примеры
При творческом подходе стримы можно использовать в маркетинге компаний любой отрасли. На примере брендов, которым удачно удалось встроить стриминг в свою маркетинговую стратегию, рассмотрим варианты его использования для продвижения.
Стримить самим и развивать свои каналы на стриминговых площадках можно, если у вас достаточно ресурсов на организацию процесса и есть четкая концепция по освоению нового маркетингового канала. Чтобы привлечь аудиторию, нужен зрелищный, увлекательный или полезный контент, который придется регулярно генерировать в трансляциях.

Эфиры магазина косметической фирмы L’Oreal на стриминговой площадке для продавцов маркетплейса «AliExpress Россия» в среднем набирают от 30 до 100 тыс. зрителей. Трансляции с обзорами бьюти-продуктов и обучающими видеоуроками по их использованию ведут официальные визажисты брендов, объединенных компанией L’Oreal. Источник
Цель при этом должна оправдывать потраченные средства: освоение нового крупного сегмента аудитории, успешный выход продуктов на рынок или получение оптимального количества лидов с конкретной стриминговой площадки, где обитают ваши клиенты.
Проще начать эксперименты со стримами, если у вас уже есть корпоративные аккаунты в соцсетях или каналы на видеохостингах с устоявшейся аудиторией. В этом случае стримы можно добавить к основному контенту.
Показывать можно все что угодно. Магазины косметики приглашают визажистов и делают макияж в прямом эфире, производители продуктов устраивают кулинарные баттлы, автосалоны ведут прямые трансляции с автопробегов, в которых участвуют их автомобили, языковые школы проводят обучающие вебинары.
Стать рекламодателем и интегрировать рекламу и PR-материалы в эфиры стримеров с подходящей аудиторией и тематикой контента. Принцип работы в этом случае такой же, как и с любой другой рекламной площадкой.
Стриминговые сервисы обычно размещают информацию для рекламодателей в открытом доступе, а стримеры, как и обычные блогеры, готовы обсуждать метрики своего канала и условия сотрудничества напрямую с рекламодателем.
Самый простой способ — купить у стриминговой площадки встроенную рекламу , которая будет транслироваться в эфирах популярных стримеров по партнерской программе. Чаще всего площадки предлагают вставку коротких рекламных роликов или всплывающие рекламные баннеры и оверлеи.

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

Комплексная интеграция бренда «Додо Пиццы» в трансляции популярных стримеров позволила уже в первые два месяца рекламной кампании охватить более 2,2 млн новых пользователей и принесла около 8 тыс. дополнительных заказов по промокодам из Twitch. Бренд использовал нативную рекламу и продакт-плейсмент во время эфиров, публикации промокодов в чатах и размещение своих баннеров на страницах стримеров. Источник
Крупные компании создают PR-коллаборации с популярными стримерами и медийными лицами, организуют турниры по киберспорту под эгидой бренда, проводят во время стримов розыгрыши с ценными призами или запускают событийные стримы.
Если вы решили, что продвижение через стримы — подходящий для вашего бизнеса формат и у вас есть идеи по его реализации, то стоит попробовать запустить тестовую рекламную кампанию. При условии правильной постановки целей, верного выбора площадки, стримера и формата материалов, результаты могут вас очень порадовать.
Глубокое погружение в Stream API Java: Понимание и Применение
В этой статье мы погрузимся в мир Stream API, узнаем, что это такое и как этим пользоваться, разберем реальные примеры и советы по лучшим практикам.
7 июля 2023 · 18 минуты на чтение

Версия Java 8 принесла множество новшеств, которые значительно упростили обработку и манипулирование данными. Одним из таких нововведений стал Stream API — эффективный инструмент для обработки коллекций в функциональном стиле.
Спонсор поста
Зачем нужен Stream API?
В прошлом, при работе с коллекциями в Java, разработчики часто прибегали к циклам и условным операторам для фильтрации, преобразования или агрегации данных. Этот подход обычно требовал большого объема кода, был трудночитаемым и подвержен ошибкам. Возьмите, например, этот код:
public void printSpecies(List seaCreatures) < SetspeciesSet = new HashSet<>(); for (SeaCreature sc : seaCreatures) < if (sc.getWeight() >= 10) speciesSet.add(sc.getSpecies()); > List sortedSpecies = new ArrayList<>(speciesSet); Collections.sort(sortedSpecies, new Comparator() < public int compare (Species a, Species b) < return Integer.compare(a.getPopulation(), b.getPopulation()); >>); for (Species s : sortedSpecies) System.out.println(s.getName()); >
Он выглядит довольно громоздким, несмотря на то, что не выполняет ничего сложного. Теперь взгляните на тот же пример, но с использованием Stream API:
public void printSpecies(List seaCreatures) < seaCreatures.stream() .filter(sc ->sc.getWeight() >= 10) .map(SeaCreature::getSpecies) .distinct() .sorted(Comparator.comparing(Species::getPopulation)) .map(Species::getName) .forEach(System.out::println); >
С приходом Stream API картина радикально изменилась. Stream API обеспечивает функциональный стиль работы с данными, предлагая более компактный, выразительный и читаемый код, а также облегчая параллельное выполнение операций.
Основы Stream API
Stream API не предлагает решения для всех возможных сценариев обработки данных. Однако, большинство задач могут быть описаны следующим общим шаблоном:
- Источник данных.
- Выполнение преобразований.
- Сохранение результата в новую структуру данных.
Если ваша задача не соответствует этому шаблону, то, возможно, использование Stream API не будет оптимальным решением.
«Стримоз» головного мозга
Это условное заболевание может возникнуть у разработчиков, которые недавно узнали о существовании Stream API. Основной симптом — необузданное желание использовать Stream API для выполнения любых операций над коллекциями.
Пример из реального мира
Представьте, что Stream API — это конвейер на рыболовецком судне. Источник — это река, полная разнообразными морскими обитателями. Мы начинаем с этой «реки» и запускаем Stream, который можно сравнить с конвейером:

- Сначала мы используем filter() для отделения рыб от всех других морских существ. Это напоминает рыбаков, которые отбирают только нужные виды рыбы из всего множества разных созданий в реке.
- Затем, с помощью map() , мы преобразуем каждую рыбу в «упаковку с рыбой». Это подобно рыболовному сету, которое собирает рыбу и укладывает ее в контейнеры.
- В конце, с помощью collect() , мы складываем все упаковки с рыбой в «грузовик» для последующей транспортировки.
Все это происходит в рамках одного непрерывного процесса, или ‘потока’. Stream API позволяет нам обрабатывать каждый элемент коллекции эффективно и последовательно, подобно конвейеру на фабрике.
Компоненты Stream API
Stream API состоит из набора компонентов и концепций, которые работают вместе, чтобы обеспечить потоковую обработку данных.

- Источник (Source) — откуда приходят данные. Это может быть коллекция, массив, файл, генератор или любой другой источник данных.
- Операции — преобразовывают и/или обрабатывают данные.
- Поток (Stream) — последовательность элементов, подлежащих параллельной или последовательной обработке.
- Пайплайн (Pipeline) — последовательность операций в потоке, применяемых к данным.
- Терминал (Terminal) — место выхода данных из потока. Терминальная операция означает окончание обработки потока и возвращает результат.
Источники даных для потоков
Stream API способен работать с разнообразными источниками данных. Это могут быть коллекции, списки, наборы, массивы, строки, файлы или даже генераторы чисел. Все эти источники могут быть легко преобразованы в потоки для последующей обработки.
Важно отметить, что при выполнении Stream исходные данные не изменяются. В результате своей работы Stream создает новую структуру данных.

Spliterator используется в основе стримов в Java и играет важную роль при параллельной обработке данных, так как именно он отвечает за разделение данных на части для независимой обработки каждым потоком.
Методы Spliterator
Spliterator описывает 4 основных метода:
- long estimateSize() возвращает количество элементов.
- tryAdvance(Consumer) принимает функциональный интерфейс Consumer , который определяет действия, которые должны быть выполнены над текущим элементом.
- int characteristics() возвращает набор характеристик текущего сплитератора.
- Spliterator trySplit() пытается разделить текущий сплитератор на два. Если операция успешна, то возвращает новый сплитератор, и уменьшает размер исходного сплитератора. Если разделение не возможно, то возвращает null .
Характеристики Spliterator
Spliterator обладает специальными характеристиками, которые сообщают об особенностях источника данных, из которого он был создан. Эти характеристики помогают в оптимизации работы потока при выполнении терминальных операций. Например, нет смысла выполнять сортировку уже отсортированной коллекции.
- ORDERED : указывает, что элементы имеют определенный порядок.
- DISTINCT : указывает, что каждый элемент уникален. Определяется по equals() .
- SORTED : указывает, что элементы отсортированы.
- SIZED : указывает, что размер источника известен заранее.
- NONNULL : указывает, что ни один элемент не может быть null .
- IMMUTABLE : указывает, что элементы не могут быть модифицированы.
- CONCURRENT : указывает, что исходные данные могут быть модифицированы без воздействия на Spliterator .
- SUBSIZED : указывает, что размер разделенных Spliterator -ов также будет известен.
В зависимости от типа коллекции, из которой получен Spliterator , будут установлены разные характеристики. Например, для коллекции Collection будет установлен флаг SIZED , для Set добавится DISTINCT , а для SortedSet еще и SORTED .
Каждая операция может менять флаги характеристик. Это важно, поскольку каждый этап обработки данных будет знать об этих изменениях, что позволяет выполнить оптимальные действия. Например, операция map() сбросит флаги SORTED и DISTINCT , так как данные могут измениться, но всегда сохранит флаг SIZED , так как размер потока не изменяется при выполнении map() .
Параллельное выполнение
Stream API предоставляет возможность параллельной обработки данных, что может способствовать увеличению производительности на многоядерных процессорах. Однако необходимо учитывать, что параллельное выполнение может внести дополнительную сложность и накладные расходы, поэтому следует использовать его обдуманно.
Для выполнения потоков в параллельном режиме можно использовать методы parallelStream() или parallel() . Без явного вызова этих методов поток будет выполняться последовательно. Для разделения коллекции на части, которые могут быть обработаны отдельными потоками, Java использует метод Spliterator.trySplit() .
С точки зрения плана выполнения, параллельная обработка схожа с последовательной, за исключением одного основного отличия. Вместо одного набора связанных операций у нас будет несколько его копий, и каждый поток будет применять эти операции к своему сегменту элементов. После завершения обработки все результаты, полученные каждым потоком, объединяются в один общий результат.

Место расположение .parallel() в Pipline
Может возникнуть вопрос, влияет ли расположение метода .parallel() в пайплайне на поведение потока?

В действительности, место, где указан .parallel() , не имеет значения, поскольку это просто устанавливает характеристику CONCURRENT . В свою очередь, sequential() удаляет эту характеристику.
Еще один важный аспект, который следует помнить о параллельных потоках, заключается в том, что Java назначает каждый фрагмент работы потоку в общем ForkJoinPool , аналогично тому, как это происходит в CompletableFuture .
Что же такое Stream?
Центральной концепцией Stream API является потоковые операции, представляющие собой ряд последовательных действий, выполняемых над данными.
Основные свойства потоков:
- Декларативность: Потоки в Java описывают, что должно быть сделано, а не конкретный способ его выполнения.
- Ленивость: Это означает, что потоки не выполняют никакой работы, пока не будет вызвана терминальная операция.
- Одноразовость: После того как терминальная операция была вызвана на потоке, этот поток больше не может быть использован. Если необходимо применить другую операцию к данным, потребуется новый поток.
- Параллельность: Несмотря на то, что потоки в Java по умолчанию выполняются последовательно, их можно легко распараллелить.
Рандомный блок
Методы Stream
Теперь, когда мы знаем, для чего нужны потоки и как они устроены изнутри, давайте рассмотрим все возможные способы работы со Stream API.
Создание Stream
Есть несколько способов создать поток с использованием Stream API. Например, вы можете создать поток из коллекции с помощью метода stream() или из массива с помощью метода of() . Как только у вас есть поток, вы можете выполнять различные операции с помощью методов, предоставляемых Stream API.
От коллекции
Вы можете создать поток из любой коллекции Java, например, списка или множества, с помощью метода stream() .
Этим способом вы будете создавать 90% своих стримов.
Collection list = new ArrayList<>(); Stream stream = list.stream();
Из массива
Поток может быть создан из массива с помощью метода Arrays.stream() .
int[] numbers = ; Stream stream = Arrays.stream(numbers).boxed();
Из строки
Поток может быть создан из строки с помощью метода chars() , который возвращает IntStream .
String str = "Hello"; IntStream stream = str.chars();
Из файла
Поток может быть создан из строк файла с помощью метода Files.lines() .
Path path = Paths.get("file.txt"); Stream stream = Files.lines(path);
Stream из Iterator-а
Многие источники данных хорошо делятся на части, что позволяет использовать преимущества параллельной обработки. Однако такие источники, как Files.lines() , Files.find() , Files.walk() , Files.list() , BufferedReader().lines() , Pattern.splitAsStream() , создают вначале Iterator , который затем трансформируется в Spliterator .
Проблема в том, что Iterator не содержит информации о размере исходного набора данных. Тем временем, для эффективной работы, Spliterator предполагает наличие информации о размере. Без этой информации Spliterator не может эффективно разбивать данные на части, что может привести к снижению эффективности параллелизма или даже к его полному отсутствию.
Генерирование
Поток может быть создан с помощью метода Stream.generate(Supplier) . Supplier должен возвращать новое значение при каждом вызове.
Stream stream = Stream.generate(() -> new Random().nextInt());
Билдер
Поток может быть создан с помощью Stream.Builder .
Stream.Builder builder = Stream.builder(); builder.add(1); builder.add(2); builder.add(3); Stream stream = builder.build();
Промежуточные методы
Мы разобрались с большинством методов создания стрима. Теперь давайте рассмотрим методы для обработки элементов.
filter(Predicate)
Этот метод используется для создания нового потока, включающего только элементы, которые удовлетворяют определенному условию. В качестве аргумента метод принимает функциональный интерфейс Predicate , задающий условие фильтрации.
Вот пример использования метода filter() для создания нового потока, который включает только четные числа из списка целых чисел.
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Stream evenNumbersStream = numbers.stream() .filter(n -> n % 2 == 0); evenNumbersStream.forEach(System.out::println); // prints 2, 4, 6, 8, 10
ORDERED : обычно сохраняется.
DISTINCT , SORTED , NONNULL , IMMUTABLE , CONCURRENT : сохраняются, если были в исходном Spliterator .
SIZED , SUBSIZED : теряются, поскольку количество элементов после фильтрации неизвестно.
map(Function)
Метод map() принимает в качестве аргумента функциональный интерфейс Function , задающий преобразование, применяемое к каждому элементу. Возвращаемый поток содержит преобразованные элементы.
Метод map() возвращает новый поток. Он не изменяет исходный поток и коллекцию. Обычно он используется для выполнения операций, таких как преобразование элементов из одного типа в другой.
List words = Arrays.asList("apple", "banana", "orange", "peach"); Stream lengthsStream = words.stream() .map(String::length); lengthsStream.forEach(System.out::println); // prints 5, 6, 6, 5
В данном примере мы с помощью map() преобразовали строку в количество символов в строке, используя короткую запись лямбды ( String::length ), так называемую ссылку на метод.
ORDERED : обычно сохраняется.
DISTINCT , SORTED : могут быть потеряны.
SIZED , SUBSIZED : обычно сохраняются.
NONNULL : может быть потеряно.
IMMUTABLE , CONCURRENT : сохраняются.
flatMap()
Метод flatMap() используется для создания одного потока из множества потоков. Он принимает функцию в качестве аргумента, которая применяется к каждому элементу исходного потока. Эта функция принимает элемент исходного потока и возвращает новый поток.
List> listOfLists = Arrays.asList( Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), Arrays.asList(7, 8, 9) ); Stream flattenedStream = listOfLists.stream() .flatMap(Collection::stream); flattenedStream.forEach(System.out::println); // prints 1, 2, 3, 4, 5, 6, 7, 8, 9
В данном примере мы начинаем со списка списков целых чисел и создаем поток с помощью метода stream() . Затем мы используем метод flatMap() для создания нового потока, включающего все целые числа из вложенных списков, путем применения метода stream() к каждому из вложенных списков. Наконец, мы используем метод forEach() для вывода каждого элемента нового потока.
Влияние на характеристики:
ORDERED : обычно сохраняется.
DISTINCT , SORTED : обычно теряются.
SIZED , SUBSIZED : теряются.
NONNULL : может быть потеряно.
IMMUTABLE , CONCURRENT : сохраняются.
Разница между map() и flatMap()
Функция map() преобразует элемент исходного потока из одного типа в другой. В отличие от этого, функция flatMap() позволяет получить новый поток из элементов коллекций, которые были внутри элементов первого потока.
distinct()
Метод distinct() возвращает новый поток, содержащий только уникальные элементы исходного потока. Дубликаты определяются на основе их естественного порядка или с использованием переданного компаратора.
Вот пример, в котором функция distinct() используется для удаления дубликатов из потока целых чисел:
List numbers = Arrays.asList(1, 2, 3, 2, 1, 4, 5, 3, 5); List uniqueNumbers = numbers.stream() .distinct() .collect(Collectors.toList()); System.out.println(uniqueNumbers); // prints [1, 2, 3, 4, 5]
ORDERED : обычно сохраняется.
DISTINCT : всегда устанавливается после операции.
SORTED : сохраняется, если исходный Spliterator был SORTED.
SIZED , SUBSIZED : теряются, поскольку количество уникальных элементов неизвестно.
NONNULL , IMMUTABLE , CONCURRENT : сохраняются.
limit(n)
Метод limit(n) возвращает новый поток, содержащий не более n элементов исходного потока. Если исходный поток содержит меньше n элементов, новый поток будет содержать все элементы исходного потока.
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List limitedNumbers = numbers.stream() .limit(5) .collect(Collectors.toList()); System.out.println(limitedNumbers); // prints [1, 2, 3, 4, 5]
ORDERED : сохраняется, если исходный Spliterator был упорядочен.
DISTINCT , SORTED , NONNULL , IMMUTABLE , CONCURRENT : сохраняются, если были в исходном Spliterator .
SIZED , SUBSIZED : могут быть установлены, если размер исходного стрима был известен и больше значения limit() , иначе могут быть потеряны.
skip(n)
Метод skip(n) возвращает новый поток, который содержит все элементы исходного потока, исключая первые n элементов. Если исходный поток содержит меньше n элементов, новый поток будет пустым.
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List skippedNumbers = numbers.stream() .skip(5) .collect(Collectors.toList()); System.out.println(skippedNumbers); // prints [6, 7, 8, 9, 10]
ORDERED : сохраняется, если исходный Spliterator был упорядочен.
DISTINCT , SORTED , NONNULL , IMMUTABLE , CONCURRENT : сохраняются, если были в исходном Spliterator .
SIZED , SUBSIZED : могут быть потеряны, если количество пропускаемых элементов неизвестно или исходный Spliterator не был SIZED или SUBSIZED . Если размер исходного стрима известен и больше значения skip, эти характеристики сохраняются.
sorted()
Метод sorted() создает новый поток, содержащий элементы исходного потока, отсортированные в порядке возрастания.
При вызове метода sorted() возвращается новый поток, содержащий те же элементы, что и исходный поток, но в отсортированном порядке.
List names = Arrays.asList("Alice", "Bob", "Charlie", "David"); List sortedNames = names.stream() .sorted() .collect(Collectors.toList()); System.out.println(sortedNames); // prints ["Alice", "Bob", "Charlie", "David"]
Если элементы исходного потока не реализуют интерфейс Comparable , может возникнуть исключение ClassCastException . Чтобы избежать этого, можно предоставить собственный компаратор в качестве аргумента метода sorted() .
ORDERED : всегда устанавливается после операции sorted() , так как элементы теперь упорядочены в соответствии с естественным порядком или порядком, определенным компаратором.
DISTINCT : сохраняется, если был в исходном Spliterator .
SORTED : всегда устанавливается.
SIZED , SUBSIZED : сохраняются, если были в исходном Spliterator .
NONNULL : сохраняется, если был в исходном Spliterator .
IMMUTABLE , CONCURRENT : сохраняются, если были в исходном Spliterator .
takeWhile(Predicate)
Метод takeWhile() создает новый поток, содержащий элементы исходного потока до тех пор, пока они удовлетворяют указанному условию. Если первый элемент потока не соответствует предикату, новый поток будет пустым.
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List takenNumbers = numbers.stream() .takeWhile(n -> n < 5) .collect(Collectors.toList()); System.out.println(takenNumbers); // prints [1, 2, 3, 4]
ORDERED : сохраняется, если исходный Spliterator был упорядочен.
DISTINCT , SORTED , NONNULL , IMMUTABLE , CONCURRENT : сохраняются, если были в исходном Spliterator.
SIZED , SUBSIZED : могут быть потеряны, поскольку количество элементов после takeWhile() неизвестно.
dropWhile(Predicate)
Метод dropWhile() возвращает новый поток, который включает все элементы исходного потока, начиная с первого элемента, не удовлетворяющего указанному условию. В момент, когда предикат возвращает false , все последующие элементы из исходного потока включаются в новый поток.
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); List droppedNumbers = numbers.stream() .dropWhile(n -> n < 5) .collect(Collectors.toList()); System.out.println(droppedNumbers); // prints [5, 6, 7, 8, 9, 10]
ORDERED : сохраняется, если исходный Spliterator был упорядочен.
DISTINCT , SORTED , NONNULL , IMMUTABLE , CONCURRENT : сохраняются, если были в исходном Spliterator.
SIZED , SUBSIZED : могут быть потеряны, поскольку количество элементов после takeWhile() неизвестно.
peek(Consumer)
Метод peek() создает новый поток, идентичный исходному, но с дополнительной операцией, применяемой к каждому элементу при его прохождении по конвейеру потока.
List numbers = Arrays.asList(1, 2, 3, 4, 5); numbers.stream() .peek(System.out::println) .collect(Collectors.toList());
В данном примере, метод peek() применяется к потоку чисел. Consumer , переданный в метод peek() , выводит каждый элемент на консоль. В процессе этого, каждый элемент, проходя по конвейеру потока, отображается на консоли, но сам поток остается неизменным.
Метод peek() удобен, когда необходимо выполнить дополнительные операции с элементами потока, например, для целей логирования, отладки или профилирования, не меняя при этом сами элементы. Но важно быть осторожным с его использованием, так как неправильное применение метода peek() может привести к нежелательным последствиям.
Поскольку peek() – это промежуточная операция, которая не предназначена для изменения элементов потока, непреднамеренные изменения могут вызвать непредсказуемые результаты при параллельном выполнении потока.
В общем случае, рекомендуется использовать peek() редко и, преимущественно, для отладки, а не как средство модификации элементов потока. Если требуется изменить элементы потока, предпочтительнее использовать метод map() .
На моей практике был всего 1 случай, когда реализовать по другому было невозможно и пришлось использовать peek() .
Терминальные методы
Как упоминалось ранее, терминальный метод запускает обработку всего потока. Рассмотрим основные из таких методов.
forEach(Consumer)
Этот метод не рекомендуется использовать в продакшене, так как он не возвращает результат. Это означает, что у него может быть только побочный эффект. Например, если мы начинаем собирать данные с помощью метода forEach() , а затем кто-то применяет параллельное выполнение к стриму, мы тут же столкнемся со всеми проблемами синхронизации.

Класс Collectors содержит набор статических методов-коллекторов, которые упрощают выполнение общих операций, таких как преобразование элементов в списки, множества и другие структуры данных.
Вот некоторые наиболее популярные методы класса Collectors :
- toList() : Этот метод возвращает коллектор, который накапливает входные элементы в новый List .
- toSet() : Этот метод возвращает коллектор, который накапливает входные элементы в новый Set .
- joining() : Возвращает коллектор, который объединяет элементы потока в единую строку.
- counting() : Возвращает коллектор, который подсчитывает количество элементов в потоке.
Вы можете быстро реализовать метод collect(Collector collector) для сбора элементов в какую-то конкретную структуру.
Stream >stream; List >list = stream.collect(Collectors.toList()); //Коллектор выше аналогичен данному коду list = stream.collect( () -> new ArrayList<>(), // определяем структуру (list, t) -> list.add(t), // определяем, как добавлять элементы (l1, l2) -> l1.addAll(l2) // и как объединять две структуры в одну );
reduce()
Метод reduce() применяется для комбинирования элементов потока в одно значение. Он отличается от метода collect() тем, что использует ассоциативную функцию, принимающую два значения и объединяющую их в одно. Например, метод reduce() можно использовать для суммирования чисел или для нахождения максимального или минимального числа.

Optional findAny()
Метод findAny() может оказаться полезным в ситуациях, когда вам нужно получить любой элемент из потока без конкретного предпочтения.
В отличие от findFirst() , который всегда возвращает первый найденный элемент потока, findAny() , при параллельном выполнении потока, может возвращать любой элемент, поскольку выбор элемента зависит от того, какой поток обработает его первым.
boolean anyMatch(Predicate)
Метод anyMatch(Predicate) используется для проверки, соответствует ли хотя бы один элемент потока указанному предикату.
boolean allMatch(Predicate)
Возвращает true , если все элементы потока удовлетворяют предикату.
Short-circuiting
Рассмотрим так называемые операции "короткого замыкания", которые прекращают обработку, как только находят нужный результат. Это значительно повышает производительность, особенно при работе с большими потоками данных. Примерами операций короткого замыкания могут служить методы anyMatch() , allMatch() , noneMatch() , findFirst() , findAny() .
Важно отметить, что поведение операций короткого замыкания может изменяться в зависимости от того, является ли поток параллельным или последовательным. Например, в параллельном потоке метод findAny() может вернуть любой элемент, удовлетворяющий условию, вместо первого попавшегося, как это происходит в последовательном потоке.
Продвинутые советы и использование
В этом разделе будут собраны различные продвинутые подходы для работы со Stream API.
Возвращать Stream вместо коллекций
Это позволит защитить вашу коллекцию внутри сущности, не позволяя ее модифицировать извне.
Так же потребитель вашего API сможет сам выбрать, какая коллекция ему нужна.

Группировка элементов
Чтобы сгруппировать данные по какому-нибудь признаку, нам надо использовать метод collect() и метод Collectors.groupingBy() .
Этот раздел "честно" позаимствован из этой статьи на хабре, чтобы сохранить эту шпаргалку у себя, если автор скроет статью или что-то случится с хабром.
Группировка списка рабочих по их должности (деление на списки)
Map> map1 = workers.stream() .collect(Collectors.groupingBy(Worker::getPosition));
Группировка списка рабочих по их должности (деление на множества)
Map> map2 = workers.stream() .collect( Collectors.groupingBy( Worker::getPosition, Collectors.toSet() ) );
Подсчет количества рабочих, занимаемых конкретную должность
Map map3 = workers.stream() .collect( Collectors.groupingBy( Worker::getPosition, Collectors.counting() ) );
Группировка списка рабочих по их должности, при этом нас интересуют только имена
Map> map4 = workers.stream() .collect( Collectors.groupingBy( Worker::getPosition, Collectors.mapping( Worker::getName, Collectors.toSet() ) ) );
Расчет средней зарплаты для данной должности
Map map5 = workers.stream() .collect( Collectors.groupingBy( Worker::getPosition, Collectors.averagingInt(Worker::getSalary) ) );
Группировка списка рабочих по их должности, рабочие представлены только именами единой строкой
Map map6 = workers.stream() .collect( Collectors.groupingBy( Worker::getPosition, Collectors.mapping( Worker::getName, Collectors.joining(", ", "") ) ) );
Группировка списка рабочих по их должности и по возрасту.
Map>> collect = workers.stream() .collect( Collectors.groupingBy( Worker::getPosition, Collectors.groupingBy(Worker::getAge) ) );
Заключение
В целом, Stream API в Java — это мощный инструмент для обработки данных, который может кардинально изменить ваш подход к программированию. Он позволяет организовывать код в читаемые и компактные последовательности операций, что делает его идеальным для работы с большими объемами данных.
Вместе с тем, важно помнить, что он не подходит для всех задач. Если ваша задача не соответствует шаблону "источник-преобразование-сбор", возможно, стоит обратиться к другим инструментам Java.
В любом случае, понимание и умение использовать Stream API является важным навыком для каждого разработчика на Java, и безусловно, этот инструмент заслуживает времени, уделенного на его изучение.