ZOFTINO.COM

RxJava Map ConcatMap FlatMap & SwitchMap Operators Difference

In this article, I am going explain the difference between map, concatMap, flatMap and switchMap operators. If you want to know about RxJava, please read my previous article RxJava with examples.

If you want to know about operators, you can read my previous articles Rxjava operators, Rxjava operator examples part 2.

Map, concatMap, flatMap and switchMap operators apply function on each item emitted by source observable.

Map operator is useful if you just want to transform or modify each item from source observable and create an observable which emits these modified items. After applying map, you will get an observable which emits the same number of items as the source observable, but it emits modified values. Modification of values emitted by source observable happens in the defined function.

 		Observable<Integer> observable = Observable.range(1, 5);
	
		Observable<String> observableFin = observable.map(new Function<Integer, String>(){
			@Override
			public String apply(Integer itemFromSource) throws Exception {
				return "maped "+itemFromSource;
			}			
		});		
		observableFin.subscribe(s -> LOGGER.info(""+s));	 

Map output

INFO: maped 1
INFO: maped 2
INFO: maped 3
INFO: maped 4
INFO: maped 5 

ConcatMap, flatMap and switchMap operators also apply function on each item emitted by source observable. But with these operators, the function, which is applied on each item of source observable, returns an observable which itself can emit multiple items.

The difference between concatMap, flatMap and switchMap operators lies in how these operators handle the returned observables from the function for each item of the source observable.

ConcatMap, flatMap and switchMap operators return final observable but how they create the final observable, after these operators receive observables from the supplied function for each item emitted by source observable, is what make them different from each other.

ConcatMap and flatMap merges items of all the observables returned by the function for each source observable item. That means concatMap and flatMap operator creates an observable that emits items of all observables returned by the function which is called for each item emitted by the source observable.

Then what is the difference between concatMap and flatMap? The difference between concatMap and flatMap is that while concatMap maintains order of items and emits items in the order, flatMap interleaves items meaning order of items is not maintained.

Then what does switchMap do? SwitchMap doesn’t merge items of observables returned by the function for each item emitted by source observable. Instead, it simply takes latest observable returned by the function and emits from it.

While emitting items from the latest observable, if new observable is returned by the function, then switchMap would abandon the current emission and pick the new latest observable from which it would emit the items.

Below example can be used to show the difference between concatMap, flatMap and switchMap operators. This example first creates an observable using range operator which emits 1 to 5 numbers. Then switchMap is applied on the returned observable passing function as input to the operator. The function’s apply method is called each time an item is emitted from integer observable. I used delay and Thread sleep to show the function of switchMap. I intentionally wrote this example in expanded form to make it easy for readers to understand the concept.

You can use the same example to see how concatMap and flatMap work by replacing switchMap with concatMap and then flatMap and then see the output to understand the difference between concatMap, flatMap and switchMap.

I provided the output of the same program for each operator.

 		Observable<Integer> observable = Observable.range(1, 5);
	
		Observable<String> observableFin = observable.switchMap(new Function<Integer, ObservableSource<String>>(){
			@Override
			public ObservableSource<String> apply(Integer itemFromSource) throws Exception {
				return Observable.just("first one "+itemFromSource,"second one "+itemFromSource, "last one "+itemFromSource).delay(10, TimeUnit.NANOSECONDS);
			}			
		});		
		observableFin.subscribe(s -> LOGGER.info(""+s));		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
		} 

SwitchMap output

INFO: first one 1
INFO: first one 5
INFO: second one 5
INFO: last one 5 

ConcatMap output

INFO: first one 1
INFO: second one 1
INFO: last one 1
INFO: first one 2
INFO: second one 2
INFO: last one 2
INFO: first one 3
INFO: second one 3
INFO: last one 3
INFO: first one 4
INFO: second one 4
INFO: last one 4
INFO: first one 5
INFO: second one 5
INFO: last one 5 

FlatMap output

INFO: first one 1
INFO: first one 2
INFO: second one 2
INFO: last one 2
INFO: first one 3
INFO: second one 3
INFO: last one 3
INFO: first one 4
INFO: second one 4
INFO: last one 4
INFO: second one 1
INFO: last one 1
INFO: first one 5
INFO: second one 5
INFO: last one 5