We have used .map() before as well. This is a functional method, and it is really easy to understand what it does--it just transforms one item to another.
Consider the given example:
Observable.just(1, 2, 3)
.map(i -> i + 1)
It will go through each number and return a new value that is higher by one. It is highly encouraged to never modify values in place, in the .map() method, but to always return a new one.
So, this approach will be bad:
Observable.just(new Date(1), new Date(2), new Date())
.map(i -> {
i.setTime(i.getTime() + 1);
return i;
})
Instead of that, prefer the following way:
Observable.just(new Date(1), new Date(2), new Date())
.map(i -> new Date(i.getTime() + 1))
This approach helps to avoid concurrent modification bugs; it is easier to debug, and it is easier to reason about.
Finally, .map() can be used to change the type of the value, as shown:
Observable.just(new Date(1), new Date(2), new Date())
.map(i -> i.toString())
Now instead of Date, a String type will be returned for the rest of the processing in the flow.
To summarize, .map() takes an item and returns a new item to be processed downstream. The newly returned item can be anything--of a different value, of a different type, or not changed at all. This can be represented in a figure, like this:

This Map transforms apples to pears. We will shortly see how all of this is related to .flatMap().