언제 RxJava 에서 map
vs 를 사용 합니까?flatMap
예를 들어 JSON이 포함 된 파일을 JSON이 포함 된 문자열에 매핑하려고합니다.
를 사용 map
하여 Exception
어떻게 든 처리해야합니다 . 그러나 어떻게? :
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
(자세한 것은 아닙니다)의 오류 처리 . 나는 떠 다니는 것에 대한 모범 사례를 보지 못했고 이것이 실제로 어떻게 사용되고 있는지 궁금합니다.
답변
map
한 이벤트를 다른 이벤트로 변환하십시오.
flatMap
하나의 이벤트를 0 개 이상의 이벤트로 변환합니다. (이것은 IntroToRx 에서 가져온 것입니다 )
json을 객체로 변환하려면 map을 사용하는 것으로 충분합니다.
FileNotFoundException을 다루는 것은 또 다른 문제입니다 (map 또는 flatmap을 사용하면이 문제가 해결되지 않습니다).
예외 문제를 해결하려면 확인되지 않은 예외로 처리하십시오. 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));
}
}
});
답변
FlatMap은 맵과 매우 유사하게 작동하지만 차이점은 적용하는 함수 가 관찰 가능 자체를 리턴하므로 비동기 작업에 대한 맵에 완벽하게 적합하다는 것입니다.
실용적인 의미에서 Map Apply 함수는 연결된 응답을 통해 변환을 수행합니다 (Observable을 반환하지 않음). FlatMap apply 함수는을 반환하지만 Observable<T>
, 메소드 내에서 비동기 호출을 수행하려는 경우 FlatMap이 권장됩니다.
요약:
- 지도는 T 유형의 객체를 반환합니다
- FlatMap은 Observable을 반환합니다.
http://blog.couchbase.com/why-couchbase-chose-rxjava-new-java-sdk 에서 명확한 예를 볼 수 있습니다 .
Couchbase Java 2.X Client는 Rx를 사용하여 편리한 방식으로 비동기 호출을 제공합니다. Rx를 사용하기 때문에 메소드 맵과 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 에서 찾을 수 있습니다.
답변
귀하의 경우 1 개의 입력과 1 개의 출력 만 있기 때문에 맵이 필요합니다.
map-제공된 함수는 단순히 항목을 받아들이고 한 번만 방출되는 항목을 반환합니다.
flatMap-제공된 함수는 항목을 승인 한 다음 “Observable”을 리턴합니다. 이는 새 “Observable”의 각 항목이 별도로 더 아래로 방출됨을 의미합니다.
코드가 당신을 위해 일을 정리 할 수 있습니다 :
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);
산출:
inside the map item1
item1
inside the flatMap item2
item2+
item2++
item2+++
답변
내가 생각하는 방식 flatMap
은 내부에 넣고 싶은 함수가를 map()
반환 할 때 사용한다는 것 Observable
입니다. 이 경우에도 여전히 사용하려고 map()
하지만 실용적이지 않습니다. 이유를 설명하려고 노력하겠습니다.
그러한 경우에 고집하기로 결정 map
했다면 Observable<Observable<Something>>
. 예를 들어, 가상의 RxGson 라이브러리를 사용했다면 (그냥 단순히 반환하는 대신) 메소드 Observable<String>
에서 를 반환하면 다음과 같습니다.toJson()
String
Observable.from(jsonFile).map(new Func1<File, Observable<String>>() {
@Override public Observable<String>> call(File file) {
return new RxGson().toJson(new FileReader(file), Object.class);
}
}); // you get Observable<Observable<String>> here
이 시점 subscribe()
에서 그러한 관찰 가능한 것은 까다로울 것 입니다. 그것 안에 Observable<String>
당신은 다시 subscribe()
가치를 얻는 데 필요한 것을 얻을 것입니다. 실용적이지 않고보기에 좋지 않습니다.
따라서 유용한 한 가지 아이디어는이 관측 가능한 관측 가능 항목을 “평평하게”하는 것입니다 (이름이 _flat_Map 인 곳을 볼 수 있습니다). RxJava는 옵저버 블을 평탄화하는 몇 가지 방법을 제공하며 단순성을 위해 병합 이 원하는 것을 가정 할 수 있습니다 . 병합은 기본적으로 많은 관측 가능 항목을 가져 와서 방출 할 때마다 방출합니다. (많은 사람들은 스위치 가 더 나은 기본값 이라고 주장 할 것입니다. 그러나 하나의 값만 내 보내면 어쨌든 상관 없습니다.)
이전 스 니펫을 수정하면 다음과 같이됩니다.
Observable.from(jsonFile).map(new Func1<File, Observable<String>>() {
@Override public Observable<String>> call(File file) {
return new RxGson().toJson(new FileReader(file), Object.class);
}
}).merge(); // you get Observable<String> here
구독 (또는 맵핑 또는 필터링 또는 …)을 구독하면 String
값을 얻을 수 있으므로 훨씬 유용 합니다. (또한 merge()
RxJava에는 이러한 변형이 존재하지 않지만 병합 개념을 이해하면 작동 방식을 이해하기를 바랍니다.)
따라서 기본적으로 merge()
이것들은 아마도 map()
관측 값 반환에 성공했을 때만 유용 하기 때문에 이것을 반복해서 입력 할 필요가 없으므로 flatMap()
속기로 작성되었습니다. 매핑 함수를 일반적인 방식으로 적용 map()
하지만 나중에 반환 된 값을 내보내는 대신 “평평하게”(또는 병합)합니다.
이것이 일반적인 사용 사례입니다. Rx를 어디에서나 사용하는 코드베이스에서 가장 유용하며 옵저버 블을 반환하는 많은 메서드가 있으며 옵저버 블을 반환하는 다른 메서드와 체인을 연결하려고합니다.
사용 된 경우에는 map()
방출 된 하나의 값만에서 방출 된 onNext()
다른 값으로 변환 할 수 있기 때문에 유용합니다 onNext()
. 그러나 여러 값으로 변환 할 수 없으며 전혀 값이 없거나 오류가 없습니다. 그리고 akarnokd 가 그의 대답에 썼 듯이 (그리고 아마도 그는 일반적으로 나보다 훨씬 똑똑하지만 적어도 RxJava에 관해서는) 당신에게서 예외를 던져서는 안됩니다 map()
. 그래서 그 대신 사용할 수있는 flatMap()
및
return Observable.just(value);
모든 것이 잘되면
return Observable.error(exception);
무언가가 실패했을 때.
자세한 내용은 https://stackoverflow.com/a/30330772/1402641에 대한 답변을 참조하십시오.
답변
문제는 RxJava에서 언제 map vs flatMap을 사용합니까? . 간단한 데모가 더 구체적이라고 생각합니다.
방출 된 항목을 다른 유형으로 변환하려는 경우 파일을 문자열로 변환하면 map 및 flatMap이 모두 작동 할 수 있습니다. 그러나 나는 더 명확하기 때문에지도 연산자를 선호합니다.
그러나 어떤 곳에서는 flatMap
마술 일을 map
할 수 있지만 할 수는 없습니다. 예를 들어, 사용자 정보를 얻고 싶지만 사용자가 로그인 할 때 먼저 ID를 가져와야합니다. 분명히 두 개의 요청이 필요하며 순서대로되어 있습니다.
의 시작하자.
Observable<LoginResponse> login(String email, String password);
Observable<UserInfo> fetchUserInfo(String userId);
다음은 두 가지 방법으로, 하나는 로그인을 반환 Response
하고 다른 하나는 사용자 정보를 가져 오는 방법입니다.
login(email, password)
.flatMap(response ->
fetchUserInfo(response.id))
.subscribe(userInfo -> {
// get user info and you update ui now
});
보시다시피 flatMap 함수가 적용되면 처음에는 사용자 ID를 가져온 Response
다음 사용자 정보를 가져옵니다. 두 개의 요청이 완료되면 UI 업데이트 또는 데이터베이스에 데이터 저장과 같은 작업을 수행 할 수 있습니다.
그러나 사용 map
하면 멋진 코드를 작성할 수 없습니다. 한마디로 flatMap
요청을 직렬화하는 데 도움이 될 수 있습니다.
답변
여기에 간단 엄지 손가락 규칙 나는 나를 사용하는 경우와 같이 결정하는 데 도움을 사용하는 것이 flatMap()
이상 map()
수신의에서가 Observable
.
map
변환 을 사용하기로 결정 했다면 변환 코드를 작성하여 객체를 올바르게 반환합니까?
변환의 최종 결과로 돌아 오는 것이 다음과 같은 경우 :
-
관찰 할 수없는 객체를 사용하면 그냥을 사용
map()
합니다. 그리고map()
그 객체를 Observable에 싸서 방출합니다. -
Observable
객체는, 당신은 사용하십시오flatMap()
. 그리고flatMap()
Observable을 풀고, 반환 된 객체를 선택하고, 자신의 Observable로 감싸서 방출합니다.
예를 들어 input param의 Titled Cased String 객체를 반환하는 titleCase (String inputParam) 메소드가 있다고 가정 해보십시오. 이 메소드의 리턴 유형은 String
또는 Observable<String>
입니다.
-
의 반환 유형
titleCase(..)
이 단순한String
경우라면map(s -> titleCase(s))
-
의 반환 형식이있는 경우
titleCase(..)
로했다Observable<String>
, 당신은 사용하십시오flatMap(s -> titleCase(s))
그 희망은 명확합니다.
답변
방금 추가하고 싶었습니다 flatMap
. 함수 내에서 사용자 정의 Observable을 실제로 사용할 필요가 없으며 표준 팩토리 메소드 / 연산자를 사용할 수 있습니다.
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);
}
}
});
일반적으로 RxJava에서 가능한 한 많은 수의 안전 장치를 배치 했더라도 가능한 경우 onXXX 메소드 및 콜백에서 (런타임-) 예외를 발생시키지 않아야합니다.