Wanneer gebruik je kaart versus flatMap in RxJava?

Wanneer gebruik je mapversus flatmapin RxJava?

Stel dat we bijvoorbeeld bestanden die JSON bevatten willen toewijzen aan strings die de JSON–

Met behulp van mapmoeten we op de een of andere manier omgaan met de Exception. Maar hoe?:

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 :(
    }
});

Met behulp van flatmapis het veel uitgebreider, maar we kunnen het probleem doorsturen door de keten van Observablesen de fout afhandelen als we ergens anders kiezen en zelfs opnieuw proberen:

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);
                }
            }
        });
    }
});

Ik hou van de eenvoud van de map, maar de foutafhandeling van flatmap(niet de breedsprakigheid). Ik heb hier geen best practices over zien rondzwerven en ik ben benieuwd hoe dit in de praktijk wordt gebruikt.


Antwoord 1, autoriteit 100%

maptransformeert de ene gebeurtenis naar de andere.
flatmaptransformeert één gebeurtenis naar nul of meer gebeurtenissen. (dit is overgenomen uit IntroToRx)

Omdat je je json naar een object wilt transformeren, zou het gebruik van een kaart voldoende moeten zijn.

Omgaan met de FileNotFoundException is een ander probleem (het gebruik van kaart of flatmap zou dit probleem niet oplossen).

Om uw Exception-probleem op te lossen, gooi het gewoon met een Non-check exception: RX zal de onError-handler voor u aanroepen.

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);
        }
    }
});

exact dezelfde versie met 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
        }
    }
});

Je kunt in de flatMap-versie ook een nieuwe Observable retourneren die gewoon een fout is.

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));
        }
    }
});

Antwoord 2, autoriteit 65%

FlatMap gedraagt ​​zich heel erg als map, het verschil is dat de functie die het toepastzelf een waarneembaar gegeven teruggeeft, dus het is perfect geschikt om asynchrone bewerkingen in kaart te brengen.

In praktische zin maakt de functie Kaart die wordt toegepast alleen een transformatie over het geketende antwoord (geen waarneembare waarde teruggevend); terwijl de functie FlatMap van toepassing is, retourneert een Observable<T>, daarom wordt FlatMap aanbevolen als u van plan bent een asynchrone aanroep te doen binnen de methode.

Samenvatting:

  • Kaart retourneert een object van het type T
  • FlatMap retourneert een waarneembaar.

Een duidelijk voorbeeld is hier te zien: http:// blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk.

Couchbase Java 2.X Client gebruikt Rx om op een gemakkelijke manier asynchrone oproepen te leveren. Omdat het Rx gebruikt, de methodekaart en FlatMap heeft, kan de uitleg in hun documentatie nuttig zijn om het algemene concept te begrijpen.

Om fouten af ​​te handelen, overschrijft u onError op uw abonnee.

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) { }
};

Het kan helpen om dit document te bekijken: http: //blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

Een goede bron over het beheren van fouten met RX is te vinden op: https://gist.github .com/daschl/db9fcc9d2b932115b679


Antwoord 3, autoriteit 54%

In jouw geval heb je een kaart nodig, aangezien er maar 1 ingang en 1 uitgang is.

kaart – geleverde functie accepteert eenvoudig een item en retourneert een item dat verder (slechts één keer) naar beneden wordt uitgezonden.

flatMap – geleverde functie accepteert een item en retourneert vervolgens een “Waarneembaar”, wat betekent dat elk item van het nieuwe “Waarneembare” verderop afzonderlijk wordt uitgezonden.

Misschien verduidelijkt code dingen voor je:

Observable.just("item1").map( str -> {
    System.out.println("inside the map " + str);
    return str;
}).subscribe(System.out::println);
Observable.just("item2").flatMap( str -> {
    System.out.println("inside the flatMap " + str);
    return Observable.just(str + "+", str + "++" , str + "+++");
}).subscribe(System.out::println);

Uitvoer:

inside the map item1
item1
inside the flatMap item2
item2+
item2++
item2+++

Antwoord 4, autoriteit 19%

Hier is een eenvoudige duimregeldie ik gebruik om me te helpen beslissen wanneer ik flatMap()moet gebruiken over map()in Rx’s Observable.

Zodra u tot de beslissing komt dat u een map-transformatie gaat gebruiken, zou u uw transformatiecode schrijven om een ​​object terug te geven, toch?

Als wat u retourneert als eindresultaat van uw transformatie is:

  • een niet-waarneembaar object is, dan zou je gewoon map()gebruiken. En map()verpakt dat object in een Observable en zendt het uit.

  • een Observableobject, dan zou je flatMap()gebruiken. En flatMap()pakt het waarneembare uit, kiest het geretourneerde object, verpakt het met zijn eigen waarneembare en zendt het uit.

Stel bijvoorbeeld dat we een methode titleCase(String inputParam) hebben die het Titled Cased String-object van de invoerparam teruggeeft. Het retourtype van deze methode kan Stringof Observable<String>zijn.

  • Als het retourtype van titleCase(..)louter Stringzou zijn, dan zou je map(s -> titleCase(s))

  • Als het retourtype van titleCase(..)Observable<String>zou zijn, dan zou je flatMap(s -> titleCase(s))

Hoop dat dit verduidelijkt.


Antwoord 5, autoriteit 10%

Ik wilde alleen toevoegen dat je met flatmapniet echt je eigen aangepaste Observable in de functie hoeft te gebruiken en dat je kunt vertrouwen op standaard fabrieksmethoden/operators:

Observable.from(jsonFile).flatMap(new Func1<File, Observable<String>>() {
    @Override public Observable<String> call(final File file) {
        try {
            String json = new Gson().toJson(new FileReader(file), Object.class);
            return Observable.just(json);
        } catch (FileNotFoundException ex) {
            return Observable.<String>error(ex);
        }
    }
});

Over het algemeen moet je vermijden (Runtime-)uitzonderingen van onXXX-methoden en callbacks te gebruiken indien mogelijk, ook al hebben we zoveel mogelijk beveiligingen in RxJava geplaatst.


Antwoord 6, autoriteit 6%

Gebruik in dat scenario een kaart, je hebt er geen nieuwe Observable voor nodig.

u moet Exceptions.propagate gebruiken, wat een wrapper is, zodat u die gecontroleerde uitzonderingen naar het rx-mechanisme kunt sturen

Observable<String> obs = 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) {
            throw Exceptions.propagate(t); /will propagate it as error
        } 
    } 
});

U moet deze fout dan afhandelen in de abonnee

obs.subscribe(new Subscriber<String>() {
    @Override 
    public void onNext(String s) { //valid result }
    @Override 
    public void onCompleted() { } 
    @Override 
    public void onError(Throwable e) { //e might be the FileNotFoundException you got }
};); 

Er is een uitstekende post voor: http: //blog.danlew.net/2015/12/08/error-handling-in-rxjava/


Antwoord 7, autoriteit 3%

RxJava-kaart versus FlatMap

Ze zijn allebei Transforming-operators, maar mapheeft een 1-1-relatie en flatmapheeft een 1-0 of veel-relatie.

  • mapen flatmapzenden streamuit met
    • map– slechts 1 element
    • flatmap– 0/veel elementen
  • mapzendt een enkel element uit en flatmapzendt een stroomvan elementen uit

Kaartoperator

map(new Function<A, B>() {
    @Override
    public B apply(A a) throws Exception {
        B b = new B(a);
        return b;
    }
})

FlatMap-operator

flatMap(new Function<A, ObservableSource<B>>() { 
    @Override
    public ObservableSource<B> apply(A a) throws Exception {
        return foo(a);
    }
})

[flatMap vs concatMap]

[Swift map vs flatMap]


Antwoord 8

In sommige gevallen kan het zijn dat u een keten van waarneembare waarden krijgt, waarbij uw waarneembare een andere waarneembare zou opleveren. ‘flatmap’ ontvouwt het tweede waarneembare dat is begraven in het eerste en geeft je direct toegang tot de gegevens die het tweede waarneembare is uitspuugt tijdens het abonneren.


Antwoord 9

Flatmap brengt waarneembare zaken in kaart.
Map wijst items toe aan items.

Flatmap is flexibeler, maar Map is lichter en directer, dus het hangt een beetje af van uw gebruik.

Als je IETS asynchroon doet (inclusief het wisselen van threads), zou je Flatmap moeten gebruiken, omdat Map niet controleert of de consument weggegooid is (onderdeel van de lichtgewichtheid)

Other episodes