Grazie
Il 29/03/2019 21:30, [email protected] [it-torino-java-jug] ha scritto:
[Attachment(s) <#TopText> from [email protected]
[it-torino-java-jug] included below]
Ciao Paolo,
anche se l'incontro non è disponibile puoi reperire la registrazione
dell'evento al JUG Milano qui
http://www.jugmilano.it/meeting-98.html
Come promesso pubblico anche una possibile soluzione all'esercizio.
Ringrazio ancora Matteo Mortari che ha ingegnosamente risolto
l'esercizio in Java, la soluzione è allegata e se non dovesse essere
chiara proverò a delucidarvi.
Ho approfittato inoltre per cogliere il suggerimento di Simone
riscrivendo la soluzione, togliendo quasi tutti gli operatori reattivi
ed utilizzando preferibilmente le coroutine.
Il secondo esercizio è:
fun countActive(): Flux<Sensor> = GlobalScope.flux {
controlUnit.getSensors().consumeEach { sensor ->
launch {
val value = iotClient.query(sensor).awaitFirst()
if (value.isFinite()) send(sensor)
}
"flux", come detto, è un generatore di flussi reattivi, per far
emettere un sensore al flusso bisogna utilizzare il metodo "send".
"consumeEach" serve per iterare sullo stream reattivo.
"launch" fa partire una coroutine, è praticamente l'analogo di "new
Thread".
"awaitFirst" sospende la coroutine aspettando il primo valore emesso
dal sensore.
La soluzione al terzo esercizio è:
fun checkSensor() = GlobalScope.flux {
val configurationDeferred = async {
database.loadConfiguration().collectList().awaitFirst() }
controlUnit.getSensors().consumeEach { sensor ->
launch {
val average = iotClient.query(sensor)
.take(3)
.collectList().awaitFirst()
.filter { it.isFinite() }
.takeIf { it.isNotEmpty() }
?.average()
val configuration =
checkNotNull(configurationDeferred.await().find { it.sensorType ==
sensor.type && it.context == sensor.context })
if (average != null && average !in
configuration.validRange) {
send(AbstractMap.SimpleEntry(sensor, average)) //
sent to Flux
}
}
}
}
"async" lancia una coroutine e ne cattura il risultato in un
"Deferred" (una sorta di CompletableFuture).
"takeIf" è il famoso operatore magico, ritorna l'offetto dse la
condizione è vera altrimenti torna "null"
"?.average()" calcola la media, il simbolo "?." invece del semplice
"." è il safe operator, cioè calcola la media della lista solo se la
lista non è null, altrimenti ritorna direttamente null. in Kotlin non
è possibile chiamare un metodo su un oggetto null, è un errore di
compilazione (in Java è un errore a runtime).
"await" sul configurationDeferred attande il risultato del deferred,
tipo "future.get()"
"find" cerca un elemento nella lista, oppure ritorna null
"checkNotNull" verifica che il parametro non sia null e lo ritorna,
altrimenti lancia un errore
"average !in validRange" è compilato esattamente come il codice Java
"!validRange.contains(average)"
Se approfondite le soluzioni proposte nei due linguaggi risulta più
evidente che gli stream reattivi hanno molti operatori solo per
sopperire a deficienze del linguaggio, nel codice Kotlin si riesce a
fare quasi tutto con async/await. Similmente è possibile estendere il
discorso per il CompletableFuture e gli Optional.
Grazie per la bella serata di ieri, arrivederci alla prossima.
Vasco