junior
Чем отличаются Mono и Flux в Project Reactor?
Mono — реактивный поток, эмитирующий 0 или 1 элемент. Flux — реактивный поток, эмитирующий от 0 до N элементов. Оба реализуют интерфейс Publisher и являются ленивыми — ничего не происходит до подписки.
Пример
// Flux: 0..N элементов
Flux<String> flux = Flux.just("Spring", "Reactor", "WebFlux");
Flux<Integer> range = Flux.range(1, 100);
Flux<Long> interval = Flux.interval(Duration.ofSeconds(1)); // бесконечный поток
// Mono: 0..1 элемент
Mono<String> mono = Mono.just("Hello");
Mono<User> user = Mono.fromCallable(() -> userRepository.findById(1L));
Mono<Void> empty = Mono.empty(); // сигнал без данных (аналог void)
Ключевые различия
| Критерий | Mono | Flux |
|---|---|---|
| Количество элементов | 0 или 1 | 0…N |
| Аналог в блокирующем мире | Optional, CompletableFuture | List, Stream |
| Типичное применение | Запрос к БД по ID, HTTP-запрос | Список сущностей, поток событий |
| Backpressure | Не актуально (максимум 1 элемент) | Критически важно |
Конвертация между Mono и Flux
Пример
// Flux -> Mono
Mono<String> first = Flux.just("A", "B", "C").next(); // первый элемент
Mono<List<String>> all = Flux.just("A", "B", "C").collectList(); // все в список
Mono<Long> count = Flux.just("A", "B", "C").count(); // количество
// Mono -> Flux
Flux<String> flux = Mono.just("A").flux(); // Mono как Flux из 1 элемента
Flux<String> repeated = Mono.just("A").repeat(3); // повторить Mono
Типичные паттерны использования в контроллере
@RestController
public class UserController {
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable Long id) {
return userRepository.findById(id); // Mono — один пользователь
}
@GetMapping("/users")
public Flux<User> getAllUsers() {
return userRepository.findAll(); // Flux — список пользователей
}
@PostMapping("/users")
public Mono<Void> createUser(@RequestBody Mono<User> user) {
return user.flatMap(userRepository::save).then(); // Mono<Void> — результат без тела
}
}
Частые ошибки
- Использовать Flux там, где достаточно Mono — если результат всегда один объект (findById), используйте Mono
- Вызывать
.block()в реактивном контексте — может привести к deadlock - Игнорировать возвращённый Mono/Flux — без подписки операция не выполнится
- Путать
mapиflatMap— map для синхронных преобразований, flatMap когда трансформация возвращает Mono/Flux
Как используется в 2026
- Mono и Flux — основа реактивного стека Spring (WebFlux, Spring Data Reactive, Spring Security Reactive)
- С Virtual Threads часть сценариев заменяется обычным блокирующим кодом
- Mono/Flux незаменимы для streaming: SSE, WebSocket, R2DBC
- Тренд: использование Mono/Flux только там, где действительно нужна реактивность
На собеседовании: минимум — назвать отличие (0…1 vs 0…N) и привести примеры использования каждого. Частая ошибка — не упомянуть ленивость (lazy): Mono/Flux без subscribe ничего не делают, а также забыть про Mono
как реактивный аналог void.