Saad Farooq
Saad Farooq

Reputation: 13402

Mapping unless exception

I have a list of Strings 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

Answers (2)

Jayson Minard
Jayson Minard

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

mfulton26
mfulton26

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

Related Questions