Wann verwenden Sie map
vs flatMap
in RxJava ?
Angenommen, wir möchten Dateien, die JSON enthalten, Strings zuordnen, die JSON enthalten.
Mit map
müssen wir uns Exception
irgendwie mit dem auseinandersetzen . Aber wie?:
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 :(
}
});
Mit flatMap
ist es viel ausführlicher, aber wir können das Problem in der gesamten Kette weiterleiten Observables
und den Fehler behandeln, wenn wir uns für einen anderen Ort entscheiden und es sogar erneut versuchen:
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);
}
}
});
}
});
Ich mag die Einfachheit der map
, aber die Fehlerbehandlung von flatmap
(nicht die Ausführlichkeit). Ich habe keine Best Practices für dieses Herumschweben gesehen und bin gespannt, wie dies in der Praxis angewendet wird.
subscriber.onError()
usw. Alle Beispiele, die ich gesehen habe, haben Fehler auf diese Weise weitergeleitet. Ist das nicht wichtig?OnErrorThrowable
are sindprivate
und SieOnErrorThrowable.from(e)
stattdessen verwenden müssen.FlatMap verhält sich sehr ähnlich wie Map, der Unterschied besteht darin, dass die Funktion angewendet wird ein Observable selbst zurückgibt, sodass es perfekt für die Zuordnung über asynchrone Operationen geeignet ist.
Im praktischen Sinne führt die Funktion Map nur eine Transformation über die verkettete Antwort durch (ohne ein Observable zurückzugeben). während die Funktion FlatMap angewendet wird, wird ein zurückgegeben
Observable<T>
angewendet wird, wird . Aus diesem Grund wird FlatMap empfohlen, wenn Sie einen asynchronen Aufruf innerhalb der Methode planen.Zusammenfassung:
Ein klares Beispiel finden Sie hier: http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk .
Der Couchbase Java 2.X-Client verwendet Rx, um auf bequeme Weise asynchrone Anrufe bereitzustellen. Da Rx verwendet wird, die Methoden map und FlatMap vorhanden sind, kann die Erläuterung in der Dokumentation hilfreich sein, um das allgemeine Konzept zu verstehen.
Um Fehler zu behandeln, überschreiben Sie onError auf Ihrem Susbcriber.
Es könnte hilfreich sein, sich dieses Dokument anzusehen: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
Eine gute Quelle zum Verwalten von Fehlern mit RX finden Sie unter: https://gist.github.com/daschl/db9fcc9d2b932115b679
quelle
In Ihrem Fall benötigen Sie eine Karte, da es nur 1 Eingabe und 1 Ausgabe gibt.
Die von map bereitgestellte Funktion akzeptiert einfach einen Artikel und gibt einen Artikel zurück, der weiter unten (nur einmal) ausgegeben wird.
Die von flatMap bereitgestellte Funktion akzeptiert ein Element und gibt dann ein "Observable" zurück, was bedeutet, dass jedes Element des neuen "Observable" weiter unten separat ausgegeben wird.
Möglicherweise klärt Code die Dinge für Sie auf:
Ausgabe:
quelle
Ich denke darüber nach, dass Sie verwenden,
flatMap
wenn die Funktion, die Sie in setzenmap()
möchten, eine zurückgibtObservable
. In diesem Fall könnten Sie immer noch versuchen, es zu verwenden,map()
aber es wäre unpraktisch. Lassen Sie mich versuchen zu erklären, warum.Wenn Sie sich in einem solchen Fall dazu entschließen, bei zu bleiben
map
, würden Sie eine bekommenObservable<Observable<Something>>
. Wenn wir in Ihrem Fall beispielsweise eine imaginäre RxGson-Bibliothek verwenden, die eine MethodeObservable<String>
aus ihrertoJson()
Methode zurückgibt (anstatt einfach eine zurückzugebenString
), sieht dies folgendermaßen aus:An diesem Punkt wäre es ziemlich schwierig,
subscribe()
eine solche Beobachtung zu machen. Darin würden Sie eine erhalten,Observable<String>
zu der Sie erneutsubscribe()
den Wert benötigen würden . Welches ist nicht praktisch oder schön anzusehen.Um es nützlich zu machen, besteht eine Idee darin, dieses Observable von Observables zu "glätten" (Sie könnten anfangen zu sehen, woher der Name _flat_Map kommt). RxJava bietet einige Möglichkeiten, um Observable zu reduzieren. Der Einfachheit halber nehmen wir an, dass das Zusammenführen das ist, was wir wollen. Beim Zusammenführen werden im Grunde genommen eine Reihe von Observablen verwendet und immer dann ausgegeben, wenn eine von ihnen ausgegeben wird. (Viele Leute würden argumentieren , dass ein Wechsel eine bessere Standardeinstellung wäre. Wenn Sie jedoch nur einen Wert ausgeben, spielt dies keine Rolle.)
Wenn wir also unser vorheriges Snippet ändern, erhalten wir:
Dies ist viel nützlicher, da Sie beim Abonnieren (oder Zuordnen oder Filtern oder ...) nur den
String
Wert erhalten. (merge()
Wohlgemerkt , eine solche Variante von gibt es in RxJava nicht, aber wenn Sie die Idee der Zusammenführung verstehen, dann hoffe ich, dass Sie auch verstehen, wie das funktionieren würde.)Also im Grunde genommen, weil solche
merge()
wahrscheinlich immer nur dann nützlich sein sollten, wenn es gelingtmap()
, ein Observable zurückzugeben, und Sie dies nicht immer wiederflatMap()
eingeben müssen , wurde es als Abkürzung erstellt. Die Zuordnungsfunktion wird wie gewohntmap()
angewendet, aber später werden die zurückgegebenen Werte nicht mehr ausgegeben, sondern "abgeflacht" (oder zusammengeführt).Das ist der allgemeine Anwendungsfall. Dies ist am nützlichsten in einer Codebasis, die überall Rx verwendet, und Sie haben viele Methoden, die Observables zurückgeben, die Sie mit anderen Methoden verketten möchten, die Observables zurückgeben.
In Ihrem Anwendungsfall ist dies ebenfalls nützlich, da
map()
nur ein emittierter WertonNext()
in einen anderen emittierten Wert umgewandelt werden kannonNext()
. Es kann jedoch nicht in mehrere Werte umgewandelt werden, überhaupt keinen Wert oder einen Fehler. Und wie akarnokd in seiner Antwort schrieb (und wohlgemerkt , er ist viel schlauer als ich, wahrscheinlich im Allgemeinen, aber zumindest wenn es um RxJava geht), sollten Sie keine Ausnahmen von Ihrer machenmap()
. Also stattdessen können SieflatMap()
und verwendenwenn alles gut geht, aber
wenn etwas ausfällt.
In seiner Antwort finden Sie einen vollständigen Ausschnitt: https://stackoverflow.com/a/30330772/1402641
quelle
Die Frage ist, wann Sie map vs flatMap in RxJava verwenden. . Und ich denke, eine einfache Demo ist spezifischer.
Wenn Sie ein ausgegebenes Element in einen anderen Typ konvertieren möchten, können in Ihrem Fall das Konvertieren von Dateien in String, Map und FlatMap funktionieren. Aber ich bevorzuge Kartenoperatoren, weil es klarer ist.
flatMap
Kann jedoch irgendwo magische Arbeit leisten , kann es abermap
nicht. Zum Beispiel möchte ich die Informationen eines Benutzers erhalten, aber ich muss zuerst seine ID erhalten, wenn sich der Benutzer anmeldet. Natürlich benötige ich zwei Anfragen und sie sind in Ordnung.Lass uns anfangen.
Hier sind zwei Methoden, eine zum Zurückgeben der Anmeldung
Response
und eine zum Abrufen von Benutzerinformationen.Wie Sie sehen, wird in der Funktion flatMap zuerst die Benutzer-ID abgerufen und
Response
dann die Benutzerinformationen abgerufen. Wenn zwei Anforderungen abgeschlossen sind, können wir unsere Aufgabe erledigen, z. B. die Benutzeroberfläche aktualisieren oder Daten in einer Datenbank speichern.Wenn Sie jedoch verwenden
map
, können Sie keinen so schönen Code schreiben. Mit einem Wort,flatMap
kann uns helfen, Anfragen zu serialisieren.quelle
Hier ist eine einfache Daumenregel , die ich verwende, um zu entscheiden, wann ich
flatMap()
siemap()
in Rx verwenden sollObservable
.Sobald Sie zu einer Entscheidung kommen, dass Sie eine beschäftigen werden
map
Transformation entschieden haben, schreiben Sie Ihren Transformationscode, um ein Objekt zurückzugeben, oder?Wenn Sie als Endergebnis Ihrer Transformation Folgendes zurückgeben:
ein nicht beobachtbares Objekt, das Sie dann nur verwenden würden
map()
. Undmap()
verpackt dieses Objekt in ein Observable und sendet es aus.ein
Observable
Objekt, dann würden Sie verwendenflatMap()
. UndflatMap()
packt das Observable aus, wählt das zurückgegebene Objekt aus, umhüllt es mit seinem eigenen Observable und gibt es aus.Angenommen, wir haben eine Methode titleCase (String inputParam), die das Titled Cased String-Objekt des Eingabeparameters zurückgibt. Der Rückgabetyp dieser Methode kann
String
oder seinObservable<String>
.Wenn der Rückgabetyp von
titleCase(..)
nur wäreString
, würden Sie verwendenmap(s -> titleCase(s))
Wenn der Rückgabetyp von
titleCase(..)
wäreObservable<String>
, würden Sie verwendenflatMap(s -> titleCase(s))
Hoffe das klärt.
quelle
Ich wollte nur hinzufügen, dass
flatMap
Sie nicht wirklich Ihre eigene Observable innerhalb der Funktion verwenden müssen und sich auf Standard-Factory-Methoden / -Operatoren verlassen können:Im Allgemeinen sollten Sie nach Möglichkeit vermeiden, (Laufzeit-) Ausnahmen von onXXX-Methoden und -Rückrufen auszulösen, obwohl wir in RxJava so viele Sicherheitsvorkehrungen wie möglich getroffen haben.
quelle
In diesem Szenario verwenden Sie Map, Sie benötigen kein neues Observable dafür.
Sie sollten Exceptions.propagate verwenden, einen Wrapper, damit Sie diese überprüften Ausnahmen an den Empfangsmechanismus senden können
Sie sollten diesen Fehler dann im Abonnenten behandeln
Es gibt einen ausgezeichneten Beitrag dafür: http://blog.danlew.net/2015/12/08/error-handling-in-rxjava/
quelle
In einigen Fällen haben Sie möglicherweise eine Kette von Observablen, wobei Ihre Observable eine andere Observable zurückgibt. 'flatmap' packt die zweite Observable aus, die in der ersten vergraben ist, und lässt Sie direkt auf die Daten zugreifen, die die zweite Observable beim Abonnieren ausspuckt.
quelle
Flatmap ordnet Observablen Observablen zu. Map ordnet Elemente Elementen zu.
Flatmap ist flexibler, aber Map ist leichter und direkter, sodass es von Ihrem Anwendungsfall abhängt.
Wenn Sie ALLES asynchron ausführen (einschließlich Thread-Wechsel), sollten Sie Flatmap verwenden, da Map nicht prüft, ob der Verbraucher bereit ist (Teil der Leichtigkeit).
quelle