Kiedy używasz map
vs flatMap
w RxJava ?
Powiedzmy na przykład, że chcemy zmapować pliki zawierające JSON na ciągi zawierające JSON--
Używając map
, musimy Exception
jakoś sobie z tym poradzić . Ale jak?:
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 :(
}
});
Używając flatMap
, jest to znacznie bardziej szczegółowe, ale możemy przekazać problem w dół Observables
i obsłużyć błąd, jeśli wybierzemy gdzie indziej, a nawet spróbujemy:
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);
}
}
});
}
});
Podoba mi się prostota obsługi map
, ale obsługa błędów flatmap
(nie gadatliwość). Nie widziałem żadnych dobrych praktyk dotyczących tego unoszenia się i jestem ciekawy, jak to jest wykorzystywane w praktyce.
subscriber.onError()
itd. Wszystkie przykłady, które widziałem, spowodowały błędy w ten sposób. Czy to nie ma znaczenia?OnErrorThrowable
sąprivate
i musisz ich użyćOnErrorThrowable.from(e)
.FlatMap zachowuje się bardzo podobnie do mapy, różnica polega na tym, że zastosowana funkcja sama zwraca obserwowalne, więc doskonale nadaje się do mapowania operacji asynchronicznych.
W sensie praktycznym funkcja Mapa stosuje tylko transformację w łańcuchowej odpowiedzi (nie zwracając Obserowalnej); podczas gdy funkcja FlatMap stosuje zwraca an
Observable<T>
, dlatego FlatMap jest zalecany, jeśli planujesz wykonać asynchroniczne wywołanie wewnątrz metody.Podsumowanie:
Jasny przykład można zobaczyć tutaj: http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk .
Klient Couchbase Java 2.X korzysta z Rx, aby w wygodny sposób zapewniać połączenia asynchroniczne. Ponieważ używa Rx, ma mapę metod i FlatMap, wyjaśnienie w ich dokumentacji może być pomocne w zrozumieniu ogólnej koncepcji.
Aby obsłużyć błędy, przesłoń onError na swoim susbcriber.
Przydałby się ten dokument: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
Dobre źródło zarządzania błędami za pomocą RX można znaleźć na stronie : https://gist.github.com/daschl/db9fcc9d2b932115b679
źródło
W twoim przypadku potrzebujesz mapy, ponieważ jest tylko 1 wejście i 1 wyjście.
dostarczona funkcja map po prostu przyjmuje element i zwraca element, który będzie emitowany dalej (tylko raz) w dół.
flatMap - dostarczona funkcja przyjmuje element, a następnie zwraca „Obserwowalny”, co oznacza, że każdy element nowego „Obserwowalnego” będzie emitowany osobno w dalszej części.
Być może kod wyczyści dla ciebie rzeczy:
Wynik:
źródło
Myślę o tym, że używasz,
flatMap
gdy funkcja, którą chcesz wstawić,map()
zwracaObservable
. W takim przypadku nadal możesz spróbować użyć,map()
ale byłoby to niepraktyczne. Pozwól, że wyjaśnię dlaczego.Jeśli w takim przypadku zdecydujesz się trzymać
map
, dostanieszObservable<Observable<Something>>
. Na przykład w twoim przypadku, gdybyśmy użyli wyimaginowanej biblioteki RxGson, która zwróciła metodęObservable<String>
z jejtoJson()
metody (zamiast po prostuString
zwrócić a ), wyglądałaby następująco:W tym momencie byłoby dość trudne
subscribe()
do takiego obserwowalnego. Wewnątrz dostaniesz coś,Observable<String>
do czego będziesz musiał ponowniesubscribe()
uzyskać wartość. Które nie jest praktyczne ani przyjemne dla oka.Aby uczynić to użytecznym, jednym z pomysłów jest „spłaszczenie” tego, co można zaobserwować (można zacząć widzieć, skąd pochodzi nazwa _flat_Map). RxJava oferuje kilka sposobów spłaszczania obserwowalnych i dla uproszczenia załóżmy, że scalenie jest tym, czego chcemy. Scalanie zajmuje zasadniczo kilka obserwowalnych i emituje za każdym razem, gdy emituje którekolwiek z nich. (Wiele osób twierdzi, że zmiana byłaby lepszym rozwiązaniem domyślnym. Ale jeśli emitujesz tylko jedną wartość, to i tak nie ma znaczenia.)
Tak więc zmieniając nasz poprzedni fragment otrzymamy:
Jest to o wiele bardziej przydatne, ponieważ subskrybując to (lub mapując, filtrując lub ...) po prostu dostajesz
String
wartość. (Również pamiętać, taki wariantmerge()
nie istnieje w RxJava, ale jeśli rozumiesz ideę scalenia, to mam nadzieję, że rozumiesz również, jak to by działało).Zasadniczo dlatego, że takie
merge()
powinny być prawdopodobnie użyteczne tylko wtedy, gdy uda się zwrócićmap()
obserwowalny, a więc nie trzeba wpisywać tego w kółko,flatMap()
został stworzony jako skrót. Stosuje funkcję mapowania tak jak normalniemap()
, ale później zamiast emitować zwracane wartości, „spłaszcza” je (lub scala).To ogólny przypadek użycia. Jest to najbardziej przydatne w bazie kodu, która używa Rx w całym miejscu i masz wiele metod zwracających obserwowalne, które chcesz połączyć z innymi metodami zwracającymi obserwowalne.
W twoim przypadku jest to również przydatne, ponieważ
map()
może przekształcić tylko jedną emitowaną wartość wonNext()
inną emitowaną wartośćonNext()
. Ale nie może przekształcić go w wiele wartości, żadnej wartości lub błędu. I jak napisał akarnokd w swojej odpowiedzi (i pamiętaj, że jest znacznie mądrzejszy ode mnie, prawdopodobnie ogólnie, ale przynajmniej jeśli chodzi o RxJava), nie powinieneś rzucać wyjątków od siebiemap()
. Zamiast tego możesz użyćflatMap()
ikiedy wszystko idzie dobrze, ale
kiedy coś zawiedzie.
Zobacz jego odpowiedź na pełny fragment: https://stackoverflow.com/a/30330772/1402641
źródło
Pytanie brzmi: Kiedy używasz map vs flatMap w RxJava? . Myślę, że proste demo jest bardziej szczegółowe.
Jeśli chcesz przekonwertować element emitowany na inny typ, w twoim przypadku konwersja pliku na String, map i flatMap może działać. Ale wolę operatora map, ponieważ jest to wyraźniejsze.
Jednak w niektórych miejscach
flatMap
może wykonywać magiczną pracę, alemap
nie może. Na przykład chcę uzyskać informacje o użytkowniku, ale najpierw muszę uzyskać jego identyfikator, gdy użytkownik się loguje. Oczywiście potrzebuję dwóch żądań i są one w porządku.Zaczynajmy.
Oto dwie metody, jedna do zwrócenia logowania
Response
, a druga do pobrania informacji o użytkowniku.Jak widać, w funkcji flatMap obowiązuje najpierw identyfikator użytkownika,
Response
a następnie pobieranie informacji o użytkowniku. Po zakończeniu dwóch żądań możemy wykonać nasze zadanie, takie jak aktualizacja interfejsu użytkownika lub zapisanie danych w bazie danych.Jednak jeśli używasz
map
, nie możesz napisać tak dobrego kodu. Jednym słowem,flatMap
może pomóc nam szeregować wnioski.źródło
Oto prosty kciuk zasada , że mogę używać jako pomoc mi zdecydować, kiedy użyć
flatMap()
ciągumap()
w RxObservable
.Gdy podejmiesz decyzję o zastosowaniu
map
transformacji, napiszesz kod transformacji, aby zwrócić jakiś obiekt, prawda?Jeśli zwracasz jako wynik końcowy transformacji:
nieobserwowalny obiekt, którego byś użył
map()
. Imap()
zawija ten obiekt w Obserowalny i emituje go.Observable
obiekt, a następnie byłoby użyćflatMap()
. IflatMap()
rozpakowuje Observable, podnosi zwrócony obiekt, otacza go swoim Observable i emituje.Powiedzmy na przykład, że mamy metodę titleCase (String inputParam), która zwraca tytułowy obiekt Cased String parametru wejściowego. Typem zwracanym tej metody może być
String
lubObservable<String>
.Jeśli typ zwrotu
titleCase(..)
miałby być zwykłyString
, wówczas użyłbyśmap(s -> titleCase(s))
Jeśli miałby
titleCase(..)
to być typ zwrotuObservable<String>
, to użyłbyśflatMap(s -> titleCase(s))
Nadzieja, która wyjaśnia.
źródło
Chciałem tylko dodać
flatMap
, że tak naprawdę nie musisz używać własnego niestandardowego Observable wewnątrz funkcji i możesz polegać na standardowych metodach / operatorach:Ogólnie rzecz biorąc, powinieneś unikać rzucania wyjątków (Runtime-) od metod onXXX i wywołań zwrotnych, jeśli to możliwe, mimo że umieściliśmy w RxJava jak najwięcej zabezpieczeń.
źródło
W tym scenariuszu użyj mapy, nie potrzebujesz do tego nowej Obserowalnej.
powinieneś użyć Exceptions.propagate, który jest opakowaniem, więc możesz wysłać te sprawdzone wyjątki do mechanizmu rx
Następnie należy obsłużyć ten błąd w subskrybencie
Jest na to świetny post: http://blog.danlew.net/2015/12/08/error-handling-in-rxjava/
źródło
W niektórych przypadkach możesz mieć łańcuch obserwowalnych, przy czym twoje obserwowalne zwrócą inne obserwowalne. rodzaj „płaskiej mapy” rozpakowuje drugi obserwowalny, który jest zakopany w pierwszym, i umożliwia bezpośredni dostęp do danych, które drugi obserwowalny wypluwa podczas subskrybowania.
źródło
Flatmap mapuje obserwowalne na obserwowalne. Mapuj elementy na przedmioty.
Flatmap jest bardziej elastyczny, ale mapa jest bardziej lekka i bezpośrednia, więc zależy to od twojej skrzynki użytkownika.
Jeśli wykonujesz JAKIEKOLWIEK asynchronię (w tym przełączanie wątków), powinieneś używać Flatmap, ponieważ Map nie sprawdzi, czy konsument został usunięty (część lekkości)
źródło