When do you use map
vs flatMap
in RxJava?
Say, for example, we want to map Files containing JSON into Strings that contain the JSON--
Using map
, we have to deal with the Exception
somehow. But how?:
Observable.from(jsonFile).map(new Func1<File, String>() { @Override public String call(File file) { try { return new Gson().toJson(new FileReader(file), Object.class); } catch (FileNotFoundException e) { // So Exception. What to do ? } return null; // Not good :( } });
Using flatMap
, it's much more verbose, but we can forward the problem down the chain of Observables
and handle the error if we choose somewhere else and even retry:
Observable.from(jsonFile).flatMap(new Func1<File, Observable<String>>() { @Override public Observable<String> call(final File file) { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { try { String json = new Gson().toJson(new FileReader(file), Object.class); subscriber.onNext(json); subscriber.onCompleted(); } catch (FileNotFoundException e) { subscriber.onError(e); } } }); } });
I like the simplicity of the map
, but the error handling of flatmap
(not the verbosity). I haven't seen any best practices on this floating around and I'm curious how this is being used in practice.
map: Transform the items emitted by this Flux by applying a synchronous function to each item. flatMap: Transform the elements emitted by this Flux asynchronously into Publishers.
The map() method wraps the underlying sequence in a Stream instance, whereas the flatMap() method allows avoiding nested Stream<Stream<R>> structure. Here, map() produces a Stream consisting of the results of applying the toUpperCase() method to the elements of the input Stream: List<String> myList = Stream.
switchMaplinkProjects each source value to an Observable which is merged in the output Observable, emitting values only from the most recently projected Observable.
flatMapObservable. Observable. returns an Observable that is the result of a function applied to an item emitted by a Single. from. Single.
map
transform one event to another. flatMap
transform one event to zero or more event. (this is taken from IntroToRx)
As you want to transform your json to an object, using map should be enough.
Dealing with the FileNotFoundException is another problem (using map or flatmap wouldn't solve this issue).
To solve your Exception problem, just throw it with a Non checked exception : RX will call the onError handler for you.
Observable.from(jsonFile).map(new Func1<File, String>() { @Override public String call(File file) { try { return new Gson().toJson(new FileReader(file), Object.class); } catch (FileNotFoundException e) { // this exception is a part of rx-java throw OnErrorThrowable.addValueAsLastCause(e, file); } } });
the exact same version with flatmap :
Observable.from(jsonFile).flatMap(new Func1<File, Observable<String>>() { @Override public Observable<String> call(File file) { try { return Observable.just(new Gson().toJson(new FileReader(file), Object.class)); } catch (FileNotFoundException e) { // this static method is a part of rx-java. It will return an exception which is associated to the value. throw OnErrorThrowable.addValueAsLastCause(e, file); // alternatively, you can return Obersable.empty(); instead of throwing exception } } });
You can return too, in the flatMap version a new Observable that is just an error.
Observable.from(jsonFile).flatMap(new Func1<File, Observable<String>>() { @Override public Observable<String> call(File file) { try { return Observable.just(new Gson().toJson(new FileReader(file), Object.class)); } catch (FileNotFoundException e) { return Observable.error(OnErrorThrowable.addValueAsLastCause(e, file)); } } });
FlatMap behaves very much like map, the difference is that the function it applies returns an observable itself, so it's perfectly suited to map over asynchronous operations.
In the practical sense, the function Map applies just makes a transformation over the chained response (not returning an Observable); while the function FlatMap applies returns an Observable<T>
, that is why FlatMap is recommended if you plan to make an asynchronous call inside the method.
Summary:
A clear example can be seen here: http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk .
Couchbase Java 2.X Client uses Rx to provide asynchronous calls in a convenient way. Since it uses Rx, it has the methods map and FlatMap, the explanation in their documentation might be helpful to understand the general concept.
To handle errors, override onError on your susbcriber.
Subscriber<String> mySubscriber = new Subscriber<String>() { @Override public void onNext(String s) { System.out.println(s); } @Override public void onCompleted() { } @Override public void onError(Throwable e) { } };
It might help to look at this document: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
A good source about how to manage errors with RX can be found at: https://gist.github.com/daschl/db9fcc9d2b932115b679
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With