You could use a fold to collect the results of each get
, but make the accumulator null
as soon as you hit a null result (and check that before you attempt each get
call). So it latches into a failed state:
typealias Result = String
data class Endpoint(val name: String, val result: Result?) {
fun get(): Result? {
println("Getting endpoint $name - result is $result")
return result
}
}
val endpoint1 = Endpoint("One", "Result 1")
val endpoint2 = Endpoint("Two", null)
val endpoint3 = Endpoint("Three", "Result 3")
val endpoints = listOf(endpoint1, endpoint2, endpoint3)
// I heard yr linter hates returns
fun resultCollector(results: List<Result>?, endpoint: Endpoint) =
results?.run {
endpoint.get()?.let { results.plus(it) }
}
fun main() {
endpoints.fold(emptyList<Result>(), ::resultCollector)
}
>> Getting endpoint One - result is Result 1
Getting endpoint Two - result is null
(end)
You could use a lambda instead of a function reference but I just wanted it to be clear - you pass a result list through the folder, and the function does a couple of null checks (checks the results
list, checks the result of the get
call). Both of those checks can evaluate to null, and that's what the function will return as the next accumulator - the endpoint code is only executed (and an actual Result
returned) if you don't hit a null
Personally I think that level of explanation means that maybe just a few early returns is much easier to follow and probably looks a whole lot neater when they're lined up too. Up to you though!