FlatMap: плоское преобразование для асинхронных подпотоков
FlatMap — мощный оператор для случаев, когда из одного элемента нужно создать подпоток (Publisher), и слить их в плоский результат. Это как map, но для асинхронных или множественных выходов: он "разворачивает" вложенные потоки. Полезен для запросов в цикле: например, для каждого пользователя — асинхронно запросить данные.
Пример на Flux:
Асинхронный пример: симулируем API-запросы.
Почему flatMap решает проблемы? В традиционных подходах (циклы с Future) вы ждёте каждый запрос, блокируя. Здесь — асинхронное слияние, без ожиданий и callback-ада: цепочка читаема.
Практические советы и подводные камни
Читаемость: цепочки операторов пишите по строкам для ясности: flux.filter(...).map(...).flatMap(...);
Ошибки: если в map/flatMap исключение — onError. Используйте handle() для условной обработки.
Производительность: в flatMap устанавливайте concurrency (default 256) для контроля параллелизма: flatMap(func, 4) — max 4 подпотока одновременно.
Камень: блокирующий код в лямбдах — сломает асинхронность. Для IO — используйте flatMap с Mono.fromCallable и publishOn(Schedulers.boundedElastic()).
Тестирование: StepVerifier.create(flux.map(...)).expectNext("ЯБЛОКО").verifyComplete();
#Java #middle #Reactor #map #filter #flatMap
FlatMap — мощный оператор для случаев, когда из одного элемента нужно создать подпоток (Publisher), и слить их в плоский результат. Это как map, но для асинхронных или множественных выходов: он "разворачивает" вложенные потоки. Полезен для запросов в цикле: например, для каждого пользователя — асинхронно запросить данные.
Пример на Flux:
Flux<String> fruits = Flux.just("яблоко", "банан");
Flux<Character> letters = fruits.flatMap(fruit -> Flux.fromArray(fruit.toCharArray())); // Из строки — поток символов
letters.subscribe(System.out::println); // Вывод: я, б, л, о, к, о, б, а, н, а, н (в возможном перемешанном порядке, если асинхронно)
Здесь flatMap берёт строку, создаёт Flux из символов и сливает всё в один поток. В отличие от map (который вернул бы Flux<Flux<Character>> — вложенный), flatMap "сплющивает".
Асинхронный пример: симулируем API-запросы.
import java.time.Duration;
Flux<String> users = Flux.just("user1", "user2");
Flux<String> data = users.flatMap(user -> Mono.just("Данные для " + user).delayElement(Duration.ofSeconds(1))); // Асинхронный подпоток с задержкой
data.subscribe(System.out::println); // Вывод через секунды: "Данные для user1", "Данные для user2" (параллельно, если scheduler позволяет)
FlatMap уважает backpressure: запрашивает у подпотоков по мере нужды. Но осторожно: если подпотоки бесконечные — рискуете перегрузкой. Параметр concurrency (flatMap(func, concurrency)) ограничивает параллелизм.
Почему flatMap решает проблемы? В традиционных подходах (циклы с Future) вы ждёте каждый запрос, блокируя. Здесь — асинхронное слияние, без ожиданий и callback-ада: цепочка читаема.
Практические советы и подводные камни
Читаемость: цепочки операторов пишите по строкам для ясности: flux.filter(...).map(...).flatMap(...);
Ошибки: если в map/flatMap исключение — onError. Используйте handle() для условной обработки.
Производительность: в flatMap устанавливайте concurrency (default 256) для контроля параллелизма: flatMap(func, 4) — max 4 подпотока одновременно.
Камень: блокирующий код в лямбдах — сломает асинхронность. Для IO — используйте flatMap с Mono.fromCallable и publishOn(Schedulers.boundedElastic()).
Тестирование: StepVerifier.create(flux.map(...)).expectNext("ЯБЛОКО").verifyComplete();
#Java #middle #Reactor #map #filter #flatMap
👍3
Что выведет код?
#Tasks
import java.util.*;
public class Task061025 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
for (Integer num : list) {
if (num == 3) {
list.remove(num);
}
}
System.out.println(list);
}
}
#Tasks
👍1
Варианты ответа:
Anonymous Quiz
33%
[1, 2]
4%
[1, 3]
13%
[1, 2, 3]
50%
ConcurrentModificationException
👍2
Вопрос с собеседований
Что произойдет, если в finally есть return?🤓
Ответ:
Если в finally прописан return , то он переопределит любые значения, возвращаемые в try или catch.
Это считается плохой практикой, так как затрудняет понимание кода и может скрывать исключения, которые должны были выброситься.
#собеседование
Что произойдет, если в finally есть return?
Ответ:
Это считается плохой практикой, так как затрудняет понимание кода и может скрывать исключения, которые должны были выброситься.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Джон Эдвард Хопкрофт (родился 7 октября 1939 года) — американский теоретик компьютерных наук, лауреат премии Тьюринга 1986 за фундаментальные достижения в алгоритмах и структурах данных.
Ви́ктор Леони́дович Матро́сов (7 октября 1950, Москва — 19 января 2015, Московская область) — советский / российский математик; профессор, доктор физико-математических наук.
1959 — космический аппарат «Луна-3» впервые совершил облёт Луны. Аппарат сделал первые фотоснимки её обратной стороны и передал изображения на Землю.
#Biography #Birth_Date #Events #07Октября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
А Вы пользуетесь этим каналом для обучения?
Anonymous Poll
67%
Да! Использую его как план, читаю статьи и смотрю видео!
10%
Да, периодически смотрю видео. Канал почти не читаю.
19%
Не знаю что я тут делаю
5%
Нет, мне проще найти в интернете или LLM.
0%
Нет. Тут невалидная информация.
🔥1
Коллекции в Java
Глава 3. Set — множества
Интерфейс Set. Особенности множеств
Интерфейс Set<E> — это часть Java Collections Framework (JCF), который представляет коллекцию уникальных элементов без дубликатов. Set является подинтерфейсом Collection, но с ключевым отличием: он не позволяет хранить одинаковые элементы. Если вы пытаетесь добавить дубликат, операция игнорируется.
Основные характеристики Set:
Уникальность элементов: Да, дубликаты не хранятся.
Упорядоченность: В общем случае нет (зависит от реализации).
Сортировка: Нет по умолчанию, но возможна в подтипах.
Время доступа (Big O): Для основных операций (add, remove, contains) — O(1) в HashSet, O(log n) в TreeSet.
Set моделирует математическое множество: элементы уникальны, нет индексации, фокус на наличии/отсутствии.
Методы Set (наследуются от Collection, но с нюансами):
boolean add(E e): Добавляет элемент, если его нет (возвращает true, если добавлен).
boolean remove(Object o): Удаляет элемент, если он есть.
boolean contains(Object o): Проверяет наличие.
int size(): Размер.
boolean isEmpty(): Пустота.
Iterator<E> iterator(): Для перебора (нет порядка по умолчанию).
void clear(): Очистка.
Нюанс: Set не имеет get(int index) — нет индексации, как в List. Перебор через Iterator или for-each.
Особенности множеств в Java
Множества в Java имеют несколько важных особенностей, которые определяют их использование:
Уникальность элементов:
Set автоматически предотвращает дубликаты на основе методов equals() и hashCode() (для HashSet) или compareTo() (для TreeSet).
Если добавить существующий элемент, add() возвращает false, коллекция не меняется.
Нюанс: Для custom классов обязательно переопределите equals() и hashCode() (используйте Objects.equals() и Objects.hash()). Без этого уникальность по ссылке, не по значению.
Отсутствие гарантированного порядка:
В HashSet порядок непредсказуем (зависит от хэша).
В LinkedHashSet — порядок вставки.
В TreeSet — сортированный порядок.
Нюанс: Не полагайтесь на порядок в HashSet — он может измениться при ресайзе.
Null элементы:
HashSet и LinkedHashSet позволяют один null.
TreeSet — нет (NullPointerException, так как сравнивает).
Нюанс: Null в Set — редко рекомендуется, но возможно.
Итерация и модификация:
Перебор через for-each или Iterator.
Нюанс: Во время итерации нельзя модифицировать Set (ConcurrentModificationException). Используйте Iterator.remove() для удаления.
Производительность:
HashSet: O(1) для add/remove/contains (средний случай).
TreeSet: O(log n), но с автосортировкой.
Нюанс: HashSet требует хорошего hashCode() — плохой приводит к O(n) worst-case.
Синхронизация:
Стандартные реализации не thread-safe. Для многопоточности: Collections.synchronizedSet(Set set) или ConcurrentHashSet (из Guava).
#Java #для_новичков #beginner #Collections #Set
Глава 3. Set — множества
Интерфейс Set. Особенности множеств
Интерфейс Set<E> — это часть Java Collections Framework (JCF), который представляет коллекцию уникальных элементов без дубликатов. Set является подинтерфейсом Collection, но с ключевым отличием: он не позволяет хранить одинаковые элементы. Если вы пытаетесь добавить дубликат, операция игнорируется.
Основные характеристики Set:
Уникальность элементов: Да, дубликаты не хранятся.
Упорядоченность: В общем случае нет (зависит от реализации).
Сортировка: Нет по умолчанию, но возможна в подтипах.
Время доступа (Big O): Для основных операций (add, remove, contains) — O(1) в HashSet, O(log n) в TreeSet.
Set моделирует математическое множество: элементы уникальны, нет индексации, фокус на наличии/отсутствии.
Методы Set (наследуются от Collection, но с нюансами):
boolean add(E e): Добавляет элемент, если его нет (возвращает true, если добавлен).
boolean remove(Object o): Удаляет элемент, если он есть.
boolean contains(Object o): Проверяет наличие.
int size(): Размер.
boolean isEmpty(): Пустота.
Iterator<E> iterator(): Для перебора (нет порядка по умолчанию).
void clear(): Очистка.
Нюанс: Set не имеет get(int index) — нет индексации, как в List. Перебор через Iterator или for-each.
Особенности множеств в Java
Множества в Java имеют несколько важных особенностей, которые определяют их использование:
Уникальность элементов:
Set автоматически предотвращает дубликаты на основе методов equals() и hashCode() (для HashSet) или compareTo() (для TreeSet).
Если добавить существующий элемент, add() возвращает false, коллекция не меняется.
Нюанс: Для custom классов обязательно переопределите equals() и hashCode() (используйте Objects.equals() и Objects.hash()). Без этого уникальность по ссылке, не по значению.
Отсутствие гарантированного порядка:
В HashSet порядок непредсказуем (зависит от хэша).
В LinkedHashSet — порядок вставки.
В TreeSet — сортированный порядок.
Нюанс: Не полагайтесь на порядок в HashSet — он может измениться при ресайзе.
Null элементы:
HashSet и LinkedHashSet позволяют один null.
TreeSet — нет (NullPointerException, так как сравнивает).
Нюанс: Null в Set — редко рекомендуется, но возможно.
Итерация и модификация:
Перебор через for-each или Iterator.
Нюанс: Во время итерации нельзя модифицировать Set (ConcurrentModificationException). Используйте Iterator.remove() для удаления.
Производительность:
HashSet: O(1) для add/remove/contains (средний случай).
TreeSet: O(log n), но с автосортировкой.
Нюанс: HashSet требует хорошего hashCode() — плохой приводит к O(n) worst-case.
Синхронизация:
Стандартные реализации не thread-safe. Для многопоточности: Collections.synchronizedSet(Set set) или ConcurrentHashSet (из Guava).
#Java #для_новичков #beginner #Collections #Set
👍6
Примеры использования Set
HashSet: Для быстрых операций без порядка.
LinkedHashSet: С сохранением порядка вставки.
TreeSet: С автосортировкой.
Нюанс: Для custom классов в TreeSet реализуйте Comparable или используйте Comparator при создании.
Как создать и использовать Set в IntelliJ IDEA
Импорт: В коде напишите Set — IDE предложит import java.util.Set; и реализацию (HashSet и т.д.).
Generics: Используйте Set для типобезопасности.
Автодополнение: При add() IDE подскажет параметры.
Отладка: В debug смотрите содержимое Set — IDE покажет элементы.
Конвертация: Из List в Set: new HashSet<>(list) — для удаления дубликатов.
Полезные советы для новичков
Выбор реализации: HashSet для скорости, LinkedHashSet для порядка, TreeSet для сортировки.
equals() и hashCode(): Всегда переопределяйте в custom классах для Set/Map (используйте @Override и Objects.hash()).
Удаление дубликатов: Set — быстрый способ: new HashSet<>(list).
Null: Избегайте в TreeSet; в HashSet — осторожно.
Итерация: For-each безопасен для чтения, но не модифицируйте во время перебора.
#Java #для_новичков #beginner #Collections #Set
HashSet: Для быстрых операций без порядка.
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<String> fruits = new HashSet<>();
fruits.add("Яблоко");
fruits.add("Банан");
fruits.add("Яблоко"); // Игнорируется
System.out.println(fruits.size()); // 2
System.out.println(fruits.contains("Банан")); // true
for (String fruit : fruits) {
System.out.println(fruit); // Порядок непредсказуем
}
}
}
Вывод: Размер 2, содержит "Банан", элементы в случайном порядке.
LinkedHashSet: С сохранением порядка вставки.
import java.util.LinkedHashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<String> fruits = new LinkedHashSet<>();
fruits.add("Яблоко");
fruits.add("Банан");
fruits.add("Апельсин");
for (String fruit : fruits) {
System.out.println(fruit); // Яблоко, Банан, Апельсин — порядок вставки
}
}
}
TreeSet: С автосортировкой.
import java.util.TreeSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> numbers = new TreeSet<>();
numbers.add(5);
numbers.add(1);
numbers.add(3);
for (Integer num : numbers) {
System.out.println(num); // 1, 3, 5 — отсортировано
}
}
}
Нюанс: Для custom классов в TreeSet реализуйте Comparable или используйте Comparator при создании.
Как создать и использовать Set в IntelliJ IDEA
Импорт: В коде напишите Set — IDE предложит import java.util.Set; и реализацию (HashSet и т.д.).
Generics: Используйте Set для типобезопасности.
Автодополнение: При add() IDE подскажет параметры.
Отладка: В debug смотрите содержимое Set — IDE покажет элементы.
Конвертация: Из List в Set: new HashSet<>(list) — для удаления дубликатов.
Полезные советы для новичков
Выбор реализации: HashSet для скорости, LinkedHashSet для порядка, TreeSet для сортировки.
equals() и hashCode(): Всегда переопределяйте в custom классах для Set/Map (используйте @Override и Objects.hash()).
Удаление дубликатов: Set — быстрый способ: new HashSet<>(list).
Null: Избегайте в TreeSet; в HashSet — осторожно.
Итерация: For-each безопасен для чтения, но не модифицируйте во время перебора.
#Java #для_новичков #beginner #Collections #Set
👍4
Что выведет код?
#Tasks
import java.util.*;
public class Task071025 {
public static void main(String[] args) {
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3));
Set<Integer> set2 = new HashSet<>(Arrays.asList(3, 2, 1));
System.out.println(set1.hashCode() == set2.hashCode());
System.out.println(set1.toString().equals(set2.toString()));
}
}
#Tasks
👍1
👍1
Вопрос с собеседований
Можно ли поймать Error?🤓
Ответ:
Технически Error можно поймать через catch, но этого не делают.
Errors сигнализируют о критических проблемах JVM (например, OutOfMemoryError, StackOverflowError), которые исправить на уровне приложения невозможно.
Их обработка только маскирует проблему.
#собеседование
Можно ли поймать Error?
Ответ:
Errors сигнализируют о критических проблемах JVM (например, OutOfMemoryError, StackOverflowError), которые исправить на уровне приложения невозможно.
Их обработка только маскирует проблему.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Хендрик Якоб (Яап) ван ден Херик (родился 8 октября 1947 года в Роттердаме) — нидерландский компьютерный учёный, профессор Университета Лейдена; известен работами по компьютерным шахматам и искусственному интеллекту.
Роберт Бертран Франс (8 октября 1960 г. – 15 февраля 2015 г.) — родом из Ямайки, американский учёный в области формальных методов, Unified Modeling Language (UML) и модельно-ориентированного развития ПО.
1978 — ядерный взрыв «Вятка» (15 килотонн).
#Biography #Birth_Date #Events #08Октября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Реактивное программирование
Комбинации потоков в Reactor: concat, merge и другие
Комбинации потоков — это как сборка пазла: вы берёте отдельные потоки событий и сливаете в один, управляя порядком, параллелизмом и обработкой. Операторы уважают жизненный цикл и обратное давление: если подписчик не успевает, запросы распределяются по источникам. Это делает системы масштабируемыми — под нагрузкой не тонут в очередях.
Concat: последовательное объединение потоков
Concat — оператор для слияния потоков по очереди: сначала все элементы первого, потом второго и так далее. Он ждёт завершения предыдущего (onComplete), прежде чем перейти к следующему. Идеален, когда порядок важен и параллелизм не нужен: например, загрузка данных по шагам.
Пример на Flux:
На Mono:
Почему concat полезен? В традиционных подходах (thenCompose в CompletableFuture) вы пишете цепочки вручную, рискуя callback-адом. Здесь — декларативно, с автоматическим backpressure: запросы идут к текущему потоку. Минус: медленный, если источники асинхронные — ждёт завершения.
Вариант: concatWith(other) на одном Flux для добавления.
Merge: параллельное слияние по готовности
Merge — для объединения потоков параллельно: элементы выдаются по мере готовности, без ожидания завершения. Порядок не гарантирован — зависит от скорости источников. Идеален для независимых событий: например, слияние логов из сервисов.
Пример:
На Mono: merge работает с Mono как с Flux'ом одного элемента.
Почему merge лучше потоков? В старых моделях (join в Executor) вы ждёте всех, блокируя. Здесь — асинхронно, с backpressure: merge распределяет запросы по источникам пропорционально. Параметр: merge(func, concurrency) для ограничения параллелизма.
Вариант: mergeWith(other) на одном Flux.
#Java #middle #Reactor #Concat #Merge #Zip #CombineLatest
Комбинации потоков в Reactor: concat, merge и другие
Комбинации потоков — это как сборка пазла: вы берёте отдельные потоки событий и сливаете в один, управляя порядком, параллелизмом и обработкой. Операторы уважают жизненный цикл и обратное давление: если подписчик не успевает, запросы распределяются по источникам. Это делает системы масштабируемыми — под нагрузкой не тонут в очередях.
Concat: последовательное объединение потоков
Concat — оператор для слияния потоков по очереди: сначала все элементы первого, потом второго и так далее. Он ждёт завершения предыдущего (onComplete), прежде чем перейти к следующему. Идеален, когда порядок важен и параллелизм не нужен: например, загрузка данных по шагам.
Пример на Flux:
import reactor.core.publisher.Flux;
import java.time.Duration;
Flux<String> first = Flux.just("Шаг 1a", "Шаг 1b").delayElements(Duration.ofSeconds(1)); // Задержка для симуляции
Flux<String> second = Flux.just("Шаг 2a", "Шаг 2b");
Flux<String> combined = Flux.concat(first, second);
combined.subscribe(System.out::println); // Вывод: "Шаг 1a" (через 1с), "Шаг 1b" (ещё 1с), "Шаг 2a", "Шаг 2b"
Здесь concat гарантирует последовательность: второй Flux стартует только после onComplete первого. Если ошибка в первом — весь поток прервётся onError.
На Mono:
Mono<String> m1 = Mono.just("A").delayElement(Duration.ofSeconds(1));
Mono<String> m2 = Mono.just("B");
Flux<String> seq = Flux.concat(m1, m2); // Mono как Flux с одним элементом
Почему concat полезен? В традиционных подходах (thenCompose в CompletableFuture) вы пишете цепочки вручную, рискуя callback-адом. Здесь — декларативно, с автоматическим backpressure: запросы идут к текущему потоку. Минус: медленный, если источники асинхронные — ждёт завершения.
Вариант: concatWith(other) на одном Flux для добавления.
Merge: параллельное слияние по готовности
Merge — для объединения потоков параллельно: элементы выдаются по мере готовности, без ожидания завершения. Порядок не гарантирован — зависит от скорости источников. Идеален для независимых событий: например, слияние логов из сервисов.
Пример:
Flux<String> slow = Flux.just("Медленный 1", "Медленный 2").delayElements(Duration.ofSeconds(2));
Flux<String> fast = Flux.just("Быстрый A", "Быстрый B").delayElements(Duration.ofMillis(500));
Flux<String> merged = Flux.merge(slow, fast);
merged.subscribe(System.out::println); // Возможный вывод: "Быстрый A" (0.5с), "Быстрый B" (ещё 0.5с), "Медленный 1" (2с), "Медленный 2" (ещё 2с)
Здесь merge отдает элементы, как только они готовы — параллельно. Если ошибка в одном — весь поток onError (по умолчанию), но можно настроить.
На Mono: merge работает с Mono как с Flux'ом одного элемента.
Почему merge лучше потоков? В старых моделях (join в Executor) вы ждёте всех, блокируя. Здесь — асинхронно, с backpressure: merge распределяет запросы по источникам пропорционально. Параметр: merge(func, concurrency) для ограничения параллелизма.
Вариант: mergeWith(other) на одном Flux.
#Java #middle #Reactor #Concat #Merge #Zip #CombineLatest
👍2
Zip: попарная комбинация элементов
Zip — объединяет элементы из потоков попарно: берёт первый от первого, первый от второго и т.д., применяя функцию для слияния. Завершается, когда любой поток исчерпан. Идеален для синхронизации: например, zip координат X и Y в точки.
Пример:
Почему zip решает проблемы? Вместо ручных семафоров или ожиданий в циклах, декларативно комбинируете асинхронные источники. Backpressure: запрашивает у всех равномерно.
CombineLatest: комбинация последних элементов
CombineLatest — выдаёт комбинацию последних элементов от каждого потока, как только любой обновляется. Не ждёт пар — всегда использует свежие. Идеален для реального времени: например, комбинация курсов валют.
Пример:
В отличие от zip (строгие пары), здесь — динамика. Backpressure: как в merge.
Другие комбинации: withLatestFrom и concatMap
WithLatestFrom: похож на combineLatest, но "master"-поток (основной) триггерит выдачу, беря последние из второстепенных. Пример: flux.withLatestFrom(other, (main, other) -> main + other).
ConcatMap: как flatMap, но последовательный (как concat внутри). Для orderly асинхронных подпотоков.
Эти дополняют: выбирайте по сценарию — последовательность (concat/concatMap), параллелизм (merge/flatMap) или синхронизация (zip/combineLatest).
Практические советы и подводные камни
Ошибки: по умолчанию onError останавливает всё — используйте onErrorResume для продолжения.
Параллелизм: в merge/flatMap устанавливайте prefetch (буфер) или concurrency для тюнинга.
Камень: бесконечные потоки в merge — рискуете OOM; добавьте take() или limitRate().
Тестирование: StepVerifier.create(Flux.merge(f1, f2)).expectNextMatches(...).verify();
#Java #middle #Reactor #Concat #Merge #Zip #CombineLatest
Zip — объединяет элементы из потоков попарно: берёт первый от первого, первый от второго и т.д., применяя функцию для слияния. Завершается, когда любой поток исчерпан. Идеален для синхронизации: например, zip координат X и Y в точки.
Пример:
Flux<Integer> xCoords = Flux.just(1, 2, 3);
Flux<Integer> yCoords = Flux.just(10, 20, 30, 40); // Лишний элемент игнорируется
Flux<String> points = Flux.zip(xCoords, yCoords, (x, y) -> "(" + x + ", " + y + ")");
points.subscribe(System.out::println); // Вывод: "(1, 10)", "(2, 20)", "(3, 30)"
Здесь zip ждёт пару: если один медленный — задерживает. Для >2 потоков: zip(tuple -> ..., flux1, flux2, flux3).
Почему zip решает проблемы? Вместо ручных семафоров или ожиданий в циклах, декларативно комбинируете асинхронные источники. Backpressure: запрашивает у всех равномерно.
CombineLatest: комбинация последних элементов
CombineLatest — выдаёт комбинацию последних элементов от каждого потока, как только любой обновляется. Не ждёт пар — всегда использует свежие. Идеален для реального времени: например, комбинация курсов валют.
Пример:
Flux<String> stockA = Flux.just("A:100", "A:110").delayElements(Duration.ofSeconds(1));
Flux<String> stockB = Flux.just("B:200").delayElements(Duration.ofSeconds(2));
Flux<String> latest = Flux.combineLatest(stockA, stockB, (a, b) -> a + " + " + b);
latest.subscribe(System.out::println); // Вывод примерно: "A:100 + B:200" (после 2с), "A:110 + B:200" (ещё 1с после)
Здесь combineLatest реагирует на изменения: при обновлении A использует последний B. Для >2: combineLatest(tuple -> ..., fluxes).
В отличие от zip (строгие пары), здесь — динамика. Backpressure: как в merge.
Другие комбинации: withLatestFrom и concatMap
WithLatestFrom: похож на combineLatest, но "master"-поток (основной) триггерит выдачу, беря последние из второстепенных. Пример: flux.withLatestFrom(other, (main, other) -> main + other).
ConcatMap: как flatMap, но последовательный (как concat внутри). Для orderly асинхронных подпотоков.
Эти дополняют: выбирайте по сценарию — последовательность (concat/concatMap), параллелизм (merge/flatMap) или синхронизация (zip/combineLatest).
Практические советы и подводные камни
Ошибки: по умолчанию onError останавливает всё — используйте onErrorResume для продолжения.
Параллелизм: в merge/flatMap устанавливайте prefetch (буфер) или concurrency для тюнинга.
Камень: бесконечные потоки в merge — рискуете OOM; добавьте take() или limitRate().
Тестирование: StepVerifier.create(Flux.merge(f1, f2)).expectNextMatches(...).verify();
#Java #middle #Reactor #Concat #Merge #Zip #CombineLatest
👍3
Что выведет код?
#Tasks
public class Task081025 {
public static void main(String[] args) {
try {
System.out.print("A");
throw new RuntimeException();
} catch (RuntimeException e) {
System.out.print("B");
throw new NullPointerException();
} finally {
System.out.print("C");
throw new IllegalArgumentException();
}
}
}
#Tasks
👍2
Вопрос с собеседований
Что лучше: throw или return кода ошибки?🤓
Ответ:
В Java принято использовать исключения (throw), а не коды ошибок.
Исключения позволяют разделить бизнес-логику и обработку ошибок, делать код чище и поддерживаемее.
Коды ошибок уместны в низкоуровневых системах, но не в Java-приложениях.
#собеседование
Что лучше: throw или return кода ошибки?
Ответ:
Исключения позволяют разделить бизнес-логику и обработку ошибок, делать код чище и поддерживаемее.
Коды ошибок уместны в низкоуровневых системах, но не в Java-приложениях.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3