Java 8 streaming
We're Cerios

Java 8 Streaming

Geschreven door Remco Hoetmer op 27 april 2014

Voor Reactive Systems zijn streaming technieken essentieel. De onlangs uitgekomen versie 8 van Java geeft daarvoor de middelen. Deze schieten echter tekort qua aansturing. Deze blog geeft aan wat je aan streaming hebt en wat ervoor nodig is om het te realiseren.

Kan men een gegevenspakketje goed vergelijken met een doosje met inhoud, gegevensstromen kan men vergelijken met een pipeline. Gegevens stromen door de pipeline van de server naar de client. Bijvoorbeeld het downloaden van een groot bestand via internet: de data komt in gedeelten binnen en wordt direct verwerkt. Dit geeft het voordeel van minimale resources: in plaats van het gehele bestand zit slecht een gedeelte van de data in het geheugen. Een ander voordeel is dat client en server van elkaar ontkoppeld zijn: doordat er een buffer tussen zit, kunnen ze op verschillende tijden en snelheden draaien.

Voor gestructureerde gegevens werkt het iets ingewikkelder maar het principe is hetzelfde. Onderstaand figuur geeft een voorbeeld hoe gegevens uit de Database naar de Browser kunnen stromen.

In de pipeline vinden er transformaties of transport plaats, om te beginnen met Data Access. Het gele stukje in het midden is het daadwerkelijke transport van de bits over Internet. Om dat mogelijk te maken, worden de gegevens vooraf ingepakt - om na transport weer uitgepakt te worden. Dit bestaat uit verschillen stappen.

  • Marshalling: vertaling van gegevens objecten naar tekstrepresentatie zoals XML
  • Encryptie: versleutelen ter bescherming tegen luisteren
  • Compressie: om het resources te minimaliseren en de snelheid te verhogen

Het inpakken en uitpakken aan weerszijden moet symmetrisch plaatsvinden.

De verwerking stopt zodra de client geen gegevens meer nodig heeft, een vorm van lazy-evaluation. Client en server zijn weliswaar ontkoppeld, maar indien de client stopt met verwerken, dan stopt naar verloop van tijd de gehele pipeline: in het diagram boven van links naar rechts. Het betekent dat tijdelijke buffers worden geleegd en uiteindelijk de database connectie wordt beƫindigd.

Met de zogenaamde InputStream en OutputStream interfaces van Java (tot en met versie 7) kan bovenstaande pipeline worden gerealiseerd. Java 8 heeft verbeterde functionaliteit: parallelle verwerking door middel van de Stream interface, aangegeven zoals in onderstaande figuur. Aan de rechterkant start een applicatie meerdere streams op. Deze streams worden vervolgens multi-threaded verwerkt. Een te verwerken object kiest dus 1 van de streams.

De streams komen uiteindelijk weer bij elkaar (zoals in het figuur) of de stream kan stoppen. Een belangrijke verbetering van Java 8 is dus parallelle verwerking. Daarnaast maakt Java 8 de API een stuk eenvoudiger: 1. door het wegvallen van het onderscheid tussen Input en Output, 2. door de lamba expressions - die de syntax beter leesbaarder maken en 3. door de automatische type inference.

Toch is er nog een verdere verbetering wenselijk: De streams kunnen nu enkel als Lijst operatie worden ingezet (of preciezer gezegd: enkel van Collections kan een stream worden gecreƫerd), maar het is nog niet als generiek mechanisme beschikbaar. Daarvoor zijn de volgende aanpassingen noodzakelijk:

Application Stream implementations

Applicaties moeten hun eigen implementatie van een stream kunnen starten. Bijvoorbeeld een stream maken op basis van een database cursor.

Exception management

Applicaties moeten excepties die kunnen optreden op een goede manier kunnen afhandelen. Je wilt niet dat de hele stream tot stilstand komt omdat er ergens een foutbericht zit.

Resource management

De benodigde resources moeten door applicaties te kunnen worden geconfigureerd: bijvoorbeeld door thread-pooling.

Voor de invulling hiervan biedt Netflix met RxJava Observables hele goed inspiratie. Uitbreiding van Java met bovenstaande aanpassingen lijkt mij gezien de opkomst van Reactive Sytems een goed speerpunt voor Java 9.

Referenties: