你什么时候在RxJava中使用map vs flatMap?

问题

你什么时候在RxJava中使用map vs flatMap?

比方说,我们想将包含JSON的文件映射到包含JSON的字符串中 -

使用map,我们必须以某种方式处理异常。但是如何?:

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

使用flatMap,它更加冗长,但我们可以将问题转发到Observables链中,如果我们选择其他地方甚至重试,则可以处理错误:

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

我喜欢 Map 的简单性,但是flatmap的错误处理(不是冗长)。我没有看到任何关于这种漂浮的最佳实践,我很好奇这是如何在实践中使用的。


#1 热门回答(102 赞)

map将一个事件转换为另一个事件.flatMap将一个事件转换为零个或多个事件。 (摘自IntroToRx)

由于你希望将json转换为对象,因此使用map应该足够了。

处理FileNotFoundException是另一个问题(使用map或flatmap无法解决此问题)。

要解决你的异常问题,只需使用Non checked异常抛出它:RX将为你调用onError处理程序。

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

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

你也可以在flatMap版本中返回一个新的Observable,它只是一个错误。

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

#2 热门回答(65 赞)

FlatMap的行为与map非常相似,区别在于它应用的函数为699944264**返回了一个可观察的本身,因此它非常适合映射异步操作。

在实际意义上,Map应用函数只是对链式响应进行转换(不返回Observable);而FlatMap应用函数返回anObservable<T>,这就是为什么如果你计划在方法内进行异步调用,建议使用FlatMap的原因。

概要:

  • Map返回T类型的对象
  • FlatMap返回一个Observable。

这里可以看到一个明显的例子:http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk

Couchbase Java 2.X客户端使用Rx以方便的方式提供异步调用。由于它使用Rx,因此它具有方法map和FlatMap,其文档中的解释可能有助于理解一般概念。

要处理错误,请覆盖你的susbcriber上的onError。

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

查看此文档可能会有所帮助:http://blog.danlew.net/2014/09/15/grokking-rxjava-part-1/

有关如何使用RX管理错误的良好来源,请访问:https://gist.github.com/daschl/db9fcc9d2b932115b679


#3 热门回答(42 赞)

在你的情况下,我认为你需要 Map ,因为只有1个输入和1个输出。

map - 提供的函数只接受一个项目并返回一个项目,该项目将进一步向下发射(仅一次)。

flatMap - 提供的函数接受一个项目,然后返回一个"Observable",意味着新的"Observable"的每个项目将进一步向下发出。

可能代码会为你清理一切。

//START DIFFERENCE BETWEEN MAP AND FLATMAP
    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);
    //END DIFFERENCE BETWEEN MAP AND FLATMAP

输出:

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