Quand utilisez-vous map
vs flatMap
dans RxJava ?
Disons, par exemple, que nous voulons mapper les fichiers contenant JSON en chaînes qui contiennent le JSON--
En utilisant map
, nous devons faire face en Exception
quelque sorte. Mais comment?:
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 :(
}
});
En utilisant flatMap
, c'est beaucoup plus verbeux, mais nous pouvons faire suivre le problème dans la chaîne Observables
et gérer l'erreur si nous choisissons ailleurs et même réessayons:
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);
}
}
});
}
});
J'aime la simplicité du map
, mais la gestion des erreurs flatmap
(pas la verbosité). Je n'ai vu aucune meilleure pratique à ce sujet et je suis curieux de savoir comment cela est utilisé dans la pratique.
subscriber.onError()
etc. Tous les exemples que j'ai vus ont acheminé des erreurs de cette façon. Cela n'a pas d'importance?OnErrorThrowable
sontprivate
et que vous devez utiliser à laOnErrorThrowable.from(e)
place.FlatMap se comporte beaucoup comme map, la différence est que la fonction qu'il applique renvoie elle-même une observable, il est donc parfaitement adapté pour mapper sur des opérations asynchrones.
Dans le sens pratique, la fonction Map applique effectue simplement une transformation sur la réponse chaînée (ne renvoyant pas d'observable); tandis que la fonction FlatMap s'applique renvoie un
Observable<T>
, c'est pourquoi FlatMap est recommandé si vous prévoyez d'effectuer un appel asynchrone à l'intérieur de la méthode.Résumé:
Un exemple clair peut être vu ici: http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk .
Le client Couchbase Java 2.X utilise Rx pour fournir des appels asynchrones de manière pratique. Puisqu'il utilise Rx, il a les méthodes map et FlatMap, l'explication dans leur documentation peut être utile pour comprendre le concept général.
Pour gérer les erreurs, remplacez onError sur votre abonné.
Il peut être utile de consulter ce document: http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/
Une bonne source sur la gestion des erreurs avec RX peut être trouvée à: https://gist.github.com/daschl/db9fcc9d2b932115b679
la source
Dans votre cas, vous avez besoin d'une carte, car il n'y a qu'une entrée et une sortie.
La fonction fournie par la carte accepte simplement un élément et renvoie un élément qui sera émis plus loin (une seule fois) vers le bas.
flatMap - la fonction fournie accepte un élément puis renvoie un "Observable", ce qui signifie que chaque élément du nouveau "Observable" sera émis séparément plus bas.
Peut-être que le code éclaircira les choses pour vous:
Production:
la source
La façon dont je pense les choses est que vous utilisez
flatMap
lorsque la fonction que vous vouliez mettre à l'intérieur demap()
renvoie un fichierObservable
. Dans ce cas, vous pourriez toujours essayer d'utilisermap()
mais ce ne serait pas pratique. Laissez-moi essayer d'expliquer pourquoi.Si dans ce cas vous décidiez de vous en tenir
map
, vous obtiendrez un fichierObservable<Observable<Something>>
. Par exemple, dans votre cas, si nous utilisions une bibliothèque RxGson imaginaire, qui retournait une méthode deObservable<String>
satoJson()
méthode (au lieu de simplement renvoyer aString
), cela ressemblerait à ceci:À ce stade, il serait assez difficile de
subscribe()
faire un tel observable. À l'intérieur de celui-ci, vous obtiendrez unObservable<String>
auquel vous auriez à nouveau besoinsubscribe()
pour obtenir la valeur. Ce qui n'est ni pratique ni agréable à regarder.Donc, pour le rendre utile, une idée est d '"aplatir" cette observable d'observables (vous pourriez commencer à voir d'où vient le nom _flat_Map). RxJava fournit quelques moyens d'aplatir les observables et, par souci de simplicité, supposons que la fusion est ce que nous voulons. Merge prend essentiellement un tas d'observables et émet chaque fois que l'un d'eux émet. (Beaucoup de gens diraient que le commutateur serait une meilleure valeur par défaut. Mais si vous n'émettez qu'une seule valeur, cela n'a pas d'importance de toute façon.)
Donc, en modifiant notre extrait de code précédent, nous obtiendrions:
C'est beaucoup plus utile, car en vous abonnant à cela (ou en mappant, ou en filtrant, ou ...) vous obtenez juste la
String
valeur. (De plus,merge()
remarquez qu'une telle variante de n'existe pas dans RxJava, mais si vous comprenez l'idée de fusion, j'espère que vous comprenez également comment cela fonctionnerait.)Donc, fondamentalement, parce que tel
merge()
ne devrait probablement jamais être utile que quand il réussit àmap()
renvoyer un observable et que vous n'avez donc pas à le taper encore et encore, aflatMap()
été créé comme un raccourci. Il applique la fonction de mappage comme d'habitudemap()
, mais plus tard, au lieu d'émettre les valeurs renvoyées, il les "aplatit" (ou les fusionne).C'est le cas d'utilisation général. C'est très utile dans une base de code qui utilise Rx partout et vous avez de nombreuses méthodes renvoyant des observables, que vous souhaitez enchaîner avec d'autres méthodes renvoyant des observables.
Dans votre cas d'utilisation, cela s'avère également utile, car
map()
vous ne pouvez transformer qu'une valeur émiseonNext()
dans une autre valeur émise dansonNext()
. Mais il ne peut pas le transformer en plusieurs valeurs, aucune valeur du tout ou une erreur. Et comme akarnokd l'a écrit dans sa réponse (et attention, il est beaucoup plus intelligent que moi, probablement en général, mais au moins quand il s'agit de RxJava), vous ne devriez pas jeter d'exceptions à votremap()
. Donc à la place, vous pouvez utiliserflatMap()
etquand tout va bien, mais
quand quelque chose échoue.
Voir sa réponse pour un extrait complet: https://stackoverflow.com/a/30330772/1402641
la source
La question est: Quand utilisez-vous map vs flatMap dans RxJava? . Et je pense qu'une simple démo est plus spécifique.
Lorsque vous souhaitez convertir un élément émis vers un autre type, dans votre cas, la conversion du fichier en String, map et flatMap peut fonctionner. Mais je préfère l'opérateur cartographique car c'est plus clair.
Cependant, dans certains endroits,
flatMap
peut faire un travail de magie maismap
ne peut pas. Par exemple, je veux obtenir les informations d'un utilisateur, mais je dois d'abord obtenir son identifiant lorsque l'utilisateur se connecte. De toute évidence, j'ai besoin de deux demandes et elles sont en ordre.Commençons.
Voici deux méthodes, une pour la connexion renvoyée
Response
et une autre pour récupérer les informations utilisateur.Comme vous le voyez, dans la fonction flatMap s'applique, dans un premier temps, j'obtiens l'identifiant de
Response
l'utilisateur, puis je récupère les informations sur l'utilisateur. Lorsque deux demandes sont terminées, nous pouvons faire notre travail, comme mettre à jour l'interface utilisateur ou enregistrer les données dans la base de données.Cependant, si vous utilisez,
map
vous ne pouvez pas écrire un code aussi agréable. En un mot,flatMap
peut nous aider à sérialiser les requêtes.la source
Voici un simple règle de pouce que j'utilise me aider à décider que quand utiliser
flatMap()
surmap()
Rx deObservable
.Une fois que vous avez décidé d'utiliser une
map
transformation, vous écririez votre code de transformation pour renvoyer un objet, n'est-ce pas?Si ce que vous retournez comme résultat final de votre transformation est:
un objet non observable alors vous utiliseriez juste
map()
. Etmap()
enveloppe cet objet dans un observable et l'émet.un
Observable
objet, alors vous utiliseriezflatMap()
. EtflatMap()
déballe l'Observable, sélectionne l'objet retourné, l'enveloppe avec son propre Observable et l'émet.Disons, par exemple, que nous avons une méthode titleCase (String inputParam) qui renvoie l'objet Titled Cased String du paramètre d'entrée. Le type de retour de cette méthode peut être
String
ouObservable<String>
.Si le type de retour de
titleCase(..)
devait être simpleString
, vous utiliseriezmap(s -> titleCase(s))
Si le type de retour
titleCase(..)
devait êtreObservable<String>
, vous utiliseriezflatMap(s -> titleCase(s))
J'espère que cela clarifie.
la source
Je voulais juste ajouter qu'avec
flatMap
, vous n'avez pas vraiment besoin d'utiliser votre propre Observable personnalisé dans la fonction et vous pouvez compter sur des méthodes / opérateurs d'usine standard:Généralement, vous devriez éviter de lancer des exceptions (Runtime-) à partir des méthodes onXXX et des rappels si possible, même si nous avons placé autant de sauvegardes que possible dans RxJava.
la source
Dans ce scénario, utilisez la carte, vous n'avez pas besoin d'un nouvel observable pour cela.
vous devez utiliser Exceptions.propagate, qui est un wrapper afin que vous puissiez envoyer ces exceptions vérifiées au mécanisme rx
Vous devez ensuite gérer cette erreur dans l'abonné
Il existe un excellent article à ce sujet: http://blog.danlew.net/2015/12/08/error-handling-in-rxjava/
la source
Dans certains cas, vous pourriez finir par avoir une chaîne d'observables, dans laquelle votre observable renverrait une autre observable. «flatmap» déballe la deuxième observable qui est enterrée dans la première et vous permet d'accéder directement aux données que la deuxième observable crache lors de l'abonnement.
la source
Flatmap mappe les observables aux observables. Mappez les éléments aux éléments.
Flatmap est plus flexible mais Map est plus léger et direct, donc cela dépend en quelque sorte de votre cas d'utilisation.
Si vous faites TOUT asynchrone (y compris le changement de thread), vous devriez utiliser Flatmap, car Map ne vérifiera pas si le consommateur est supprimé (partie de la légèreté)
la source