When you don't need a map

When you don't need a map

Here's a sketch of how one could listen to connectivity changes on Android via an Observable of NetworkInfo:

val networkInfo: Observable<NetworkInfo> = ...

networkInfo
    .map { it.isConnected }
    .subscribe { onConnectivityChange(it) }

While it works as expected, I would argue that the map() is unnecessary. You could do the transformation in the subscriber just as easily:

networkInfo
    .subscribe { onConnectivityChange(it.isConnected) }

While ditching map() provides a tiny performance boost, I'm not concerned about that. The important advantage is that the code is simpler.

I often see people (myself included) overusing map(). We learn about functional programming and become enamored with pure and simple functions. We forget that it can be simpler to forego a function altogether.


When is map() useful?

One case is when you're feeding values into other operators:

networkInfo
    .map { it.isConnected }
    .distinctUntilChanged()
    .subscribe { onConnectivityChange(it) }

By mapping to Boolean first, distinctUntilChanged() will only fire when isConnected changes. We can safely ignore any other state changes that NetworkInfo may go through.

(Note that map() is still not strictly necessary here because we could use distinctUntilChanged() with a key selector. I'm trying to keep the examples here simple.)

A second case is when you're passing around an Observable and you want to expose a specific type:

fun isConnectedObservable(): Observable<Boolean> {
  return networkInfo.map { it.isConnected }
}

The function above allows you to use an Observable<NetworkInfo> privately in a class without exposing it to the rest of the world.

Finally, map() is useful is when you're doing something expensive and threading is involved:

someObservable
    .map { expensiveCalculation(it) }
    .subscribeOn(Schedulers.computation())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe { ... }

You wouldn't want to run expensiveCalculation() on the main thread, so you have to run it before you get to the subscriber.

I'm sure there are other cases I'm missing here; let me know in the comments.