Reputation: 13402
I have a list of String
s representing serialized data that I want to map
to a list of objects. I use the following code:
strings.map { gson.fromJson(it, Model::class.java) }
// .doOtherStuff
However, sometimes there is a parsing error and the stream just stop, I would like to able to recover the list up until the point of failure. For example, if the error occurs at item 7, I would like doOtherStuff
to get the 6 items that were successfully processed.
What's the most idiomatic way to do this? I can filter the list to see if the parsing will succeed but that's an expensive operation being doing twice.
Upvotes: 5
Views: 6928
Reputation: 85946
You can treat an exception as null
and then filter the nulls.
val models = modelsInJson.mapNotNull { json ->
try {
gson.fromJson(json, Model::class.java)
} catch (ex: WhateverException) {
// TODO: logging here?
null
}
}
Replace WhateverException
with the correct one for the type of errors you want to handle, other errors can still stop the processing.
Upvotes: 18
Reputation: 31234
What you are looking for seems to be a combination of map
and takeWhile
. You can always roll your own. e.g. The following is adapted from the sources of mapNotNull
and takeWhile
:
inline fun <T, R : Any> Iterable<T>.mapWhileNotNull(transform: (T) -> R?): List<R> {
return mapWhileNotNullTo(ArrayList<R>(), transform)
}
inline fun <T, R : Any, C : MutableCollection<in R>> Iterable<T>.mapWhileNotNullTo(destination: C, transform: (T) -> R?): C {
for (element in this) {
val transformed = transform(element)
if (transformed == null) {
break
} else {
destination.add(transformed)
}
}
return destination
}
Now you can map an iterable up to a transform invocation that results in null
and, like Jayson Minard's example, you can map whatever exception you need to null
:
strings.mapWhileNotNull {
try {
gson.fromJson(it, Model::class.java)
} catch (e: JsonSyntaxException) {
null
}
}
// .doOtherStuff
Upvotes: 3