JavaRx_reactive_future_blog

Koska RxJava on nyt teoriassa täysin hallussa, on aika kokeilla sitä käytännössä. Graafinen käyttöliittymä tarjoaa hyvän leikkikentän käytännön tekemiseen. Tähän tarkoitukseen sopii hyvin JavaFX, jossa on muihin vaihtoehtoihin verrattuna parempi tuki asynkroniselle ohjelmoinnille. JavaFX on Javan uusin (ja jo kolmas AWT:n ja Swingin jälkeen) työpöytäkäyttöliittymäkirjasto. JavaFX:n ja RxJavan yhteenliittämiseen on myös olemassa valmis kirjasto, mielikuvituksellisesti nimetty RxJavaFX, mutta tässä esimerkissä käytetään vain RxJavaa ja JavaFX:ää, jotta pääsemme tekemään itse enemmän. Esimerkkisovelluksena kehitetään Wikipedia-selain, jolla voi hakea hakusanalla ehdotuksia suomenkielisestä Wikipediasta. Esimerkki on ryöstetty Principles of Reactive Programming -kurssilta, jossa käytettiin Swingiä ja Scalaa. Esimerkkikoodi löytyy GitHubista. Tässä keskitytään koodin reaktiivisiin osuuksiin.

Aloitetaan muussa koodissa käytettävillä apufuktioilla. Ensimmäinen osuus esittää apufunktiot Observablejen käyttöön.

fromEvent, fromProperty ja fromFuture– funktiot toteuttavat tapahtumien, propertyjen ja futurejen sovittamisen Observableksi. Päinvastaiseen suuntaan on funktiot toProperty ja toObservableList, jotka muuttavat Observablet JavaFX:n käyttöön Propertyksi tai ObservableListiksi. Funktio recovered poistaa Observablesta virheet nostamalla Observablen sisällön Optionaliksi, joka ei virhetilanteessa sisällä arvoa. Tämä aiheuttaa sen, että Observable ei katkea virheen tapahtuessa. timedOut-funktio määrittää aikakatkaisulle yksinkertaisemman käytön.

Toinen osuus apufunktioita sisältää Scheduler-toteutuksen, jolla saadaan JavaFX:n tapahtumasäie käyttöön RxJavaan.

Näitä apufunktioita käytetään sovelluksen oleellisimmassa osuudessa. Seuraava koodinpätkä on sovelluksen käyttöliittymän ja Wikipedian palvelimille juttelevan osuuden yhdistävä logiikka.

suggestionStream on Observable, joka yhdistää jokaisesta käyttäjän kirjoittamasta hakutermistä (tekstikenttään searchTerm)  tehtävästä ehdotushausta saadun Observablen yhdeksi Observable-putkeksi. Jotta näitä hakuja ei tehdä turhaan liikaa, odotetaan puoli sekuntia, että käyttäjä oikeasti lopettaa kirjoituksen, ennen kuin varsinainen haku tehdään. Tämän toiminnallisuuden toteuttaa debounce-metodi. Tästä lopputuloksena tuotetulle Observablelle kutsutaan share, jotta kun sitä myöhemmin käytetään useamman kerran, niin tehdään haut vain kertaalleen. Seuraavaksi suggestionList-listanäkymään asetetaan listaksi suggestionStreamista löytyvä uusin lista.

pages on vastaava Observable, mutta se yhdistää jokaisesta listanäkymän valinnasta tehtävän sivun haun yhdeksi Observable-putkeksi. Myös tälle kutsutaan share, jotta hakuja ei turhaan toisteta. pages-Observable liitetään web-näkymään lataamalla näkymään ladattu sivu.

Virheiden varalta sekä ehdotukset että sivut yhdistetään status-ilmoitukseen, johon tulee viesti, kun jokin toiminto on epäonnistunut.

Tällä koodilla siis saadaan kaikki toimimaan oikeissa säikeissä, (tyhmä) virheiden hallinta, viivästetty haku ja yhdistettyä Observableista mitään tietämättömät osat toisiinsa.

Seuraavassa koodinpätkässä on hakujen suoritus. Oleellinen osuus on Futuren muuttaminen Observableksi ja hakujen suorittaminen asynkronisesti Java 8:n CompletableFuturea käyttäen.

Verrattuna Scala-versioon, jonka olin aiemmin tehnyt, Java 8:lla kehitetty versio oli yllättävänkin hyvä. Laajennusmetodit ovat Observablejen kanssa Scalassa miellyttävämpiä käyttää, koska niitä pystyy sujuvasti ketjuttamaan. Yleisesti ottaen en laajennusmetodeista pidä, mutta tässä tapauksessa koodajaan hämääminen voisi olla perusteltua. Toinen Scala-version hyöty on sujuvampi käyttöliittymän rakentaminen (Mika on kertonut tästä enemmän). Muitakin parempia puoli Scala-versiossa oli, mutta niistä olisi myös Javassa saanut parempia muutamalla kirjastolla HTTP:n ja XML:n käsittelyyn.

Tämän esimerkin koodeista voi nähdä, että olemassa olevan koodin sovittaminen Observableksi ei ole vaikeaa. Koska sen seurauksena saa vielä käyttöönsä kasapäin valmiita ominaisuuksia ja oma asynkroninen koodi muodostuu selkeämmäksi, ei ole syytä jättää reaktiivisia laajennuksia kokeilematta. Tulevaisuus on reaktiivinen.