Zpět na domů

Stream API vs Flux: rozdíly pro Java vývojáře | Průvodce

Článek analyzuje architektonické rozdíly mezi Stream API a Flux z Project Reactor. Jsou zváženy klíčové aspekty: model provádění, zpracování chyb, podpora backpressure a scénáře použití. Uvedeny praktické příklady transformace dat a doporučení pro výběr nástroje.

Stream API proti Flux: jak se nezmýlit při výběru nástroje?
Advertisement 728x90

# Stream API vs Flux: architektonické rozdíly a praktické použití

Porozumění rozdílům mezi Stream API a Flux je klíčové pro Java vývojáře pracující s asynchronními systémy. Navzdory podobnosti metod (filter, map, limit) tyto nástroje řeší zásadně odlišné úkoly. Stream API je určen pro zpracování konečných kolekcí v synchronním režimu, zatímco Flux z Project Reactor je navržen pro reaktivní zpracování proudových dat s podporou backpressure a asynchronnosti. Tento článek odhaluje klíčové architektonické rozdíly a pomáhá vybrat správný nástroj pro konkrétní úkol.

Základy Stream API: synchronní zpracování kolekcí

Stream API je vestavěný mechanismus v Javě pro deklarativní zpracování kolekcí. Jeho klíčová vlastnost: práce s konečnými sadami dat v rámci jednoho vlákna provádění. Při volání .stream() se vytvoří sekvenční proud, který zpracovává prvky ve stejném vlákně, kde byl zahájen (např. main-vlákně).

Důležité je pamatovat na rozdělení operací:

Google AdInline article slot
  • Meziprodukční operace (filter, map, flatMap, limit, skip) — tvoří řetězec transformací bez okamžitého provedení. Vrátí nový proud a mohou být kombinovány v neomezeném počtu.
  • Terminální operace (collect, forEach, reduce) — spustí provedení celého řetězce a uzavřou proud. Po jejich volání není možné proud znovu použít.

Prozkoumejme příklad filtrování a transformace dat:

List<Integer> numbers = List.of(1, 2, 3, 4, 5);
numbers.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * 2)
    .forEach(System.out::println); // 4, 8

Zde:

  • filter nechá sudá čísla
  • map zdvojnásobí každý prvek
  • forEach spustí provedení a vypíše výsledek

Kritické omezení Stream API spočívá v jednorázovém použití. Pokus o opakované volání terminální operace vede k IllegalStateException. To je zásadní rozdíl oproti reaktivním proudům.

Google AdInline article slot

Flux: reaktivní zpracování proudových dat

Flux z Project Reactor implementuje specifikaci Reactive Streams určenou pro asynchronní zpracování neomezených proudů dat. Na rozdíl od Stream API Flux podporuje:

  • Nesynchronní provedení
  • Backpressure (regulaci rychlosti spotřeby dat)
  • Zpracování chyb prostřednictvím reaktivních operátorů
  • Přihlášení k událostem v libovolném vlákně

Klíčové architektonické rozdíly:

  • Terminální operace.subscribe() je povinná pro spuštění zpracování. Bez ní zůstává Flux „studený“ a negeneruje data.
  • Lenivá inicializace — data se generují až po přihlášení.
  • Podpora neomezených proudů — Flux může pracovat s nekonečnými zdroji (např. senzorová data v reálném čase).

Příklad ekvivalentní operace ve Flux:

Google AdInline article slot
Flux.just(1, 2, 3, 4, 5)
    .filter(n -> n % 2 == 0)
    .map(n -> n * 2)
    .subscribe(System.out::println); // 4, 8

Zde .subscribe() nejen spustí zpracování, ale také řídí životní cyklus proudu. Flux může zpracovávat chyby prostřednictvím .onErrorResume() a regulovat proud pomocí .limitRate().

Kritické rozdíly: tabulka porovnání

Pro přehlednost shrneme klíčové rozdíly do strukturovaného seznamu:

  • Model provádění

- Stream API: synchronní, blokující zpracování

- Flux: asynchronní, neblokující zpracování s podporou backpressure

  • Typ dat

- Stream API: pracuje pouze s konečnými kolekcemi

- Flux: podporuje konečné i nekonečné proudy

  • Zpracování chyb

- Stream API: výjimky se šíří přímo (vyžadují try/catch)

- Flux: vestavěné zpracování chyb prostřednictvím operátorů (onErrorResume, retry)

  • Opakované použití

- Stream API: jednorázové použití po terminální operaci

- Flux: vícenásobné přihlášení k jednomu proudu (za předpokladu správné konfigurace)

  • Paralelismus

- Stream API: .parallelStream() distribuuje úlohy po jádrech CPU

- Flux: .publishOn() a .subscribeOn() řídí kontext provádění

Praktický případ: transformace dat v reálných scénářích

Prozkoumejme úlohu aktualizace dat v kolekci. Máme HashMap se zaměstnanci a jejich stupni. Je požadováno:

  • Pro Junior zaměstnance změnit stupeň na Middle
  • Přidat označení „(povýšen)"
  • Vrátit aktualizovanou strukturu

Realizace přes Stream API:

Map<String, String> updatedEmployees = employees.entrySet().stream()
    .map(entry -> {
        String grade = entry.getValue();
        if ("Junior".equals(grade)) {
            return Map.entry(entry.getKey(), "Middle (increased)");
        }
        return entry;
    })
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Totéž scénář přes Flux:

Map<String, String> updatedEmployees = Flux.fromStream(employees.entrySet().stream())
    .map(entry -> {
        if ("Junior".equals(entry.getValue())) {
            return Map.entry(entry.getKey(), "Middle (increased)");
        }
        return entry;
    })
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
    .block();

Klíčové rozdíly v realizaci:

  • Flux vyžaduje explicitní .block() pro získání výsledku (porušuje reaktivní přístup)
  • Stream API blokuje vlákno provádění do dokončení operace
  • Pro reaktivní systémy je preferován neblokující přístup přes .subscribe()

Co je důležité: klíčové závěry

  • Stream API — optimální pro synchronní zpracování konečných kolekcí v rámci jednoho vlákna. Používejte pro ETL-operace, transformace dat v obchodní logice.
  • Flux — řeší úlohy asynchronního zpracování proudových dat. Používejte při práci se síťovými požadavky, senzory, event bus.
  • Backpressure — kritická funkce Flux, která v Stream API chybí. Zajišťuje stabilitu systému při vysoké zátěži.
  • Chyby provádění — v Flux se zpracovávají reaktivně, v Stream API vyžadují tradiční try/catch.
  • Výkon — Stream API je efektivnější pro krátké synchronní operace, Flux pro dlouhé asynchronní procesy.

— Editorial Team

Advertisement 728x90

Číst dál