안녕하세요. 메로나입니다.
오늘은 데이터 변환 연산자에 대해 공부하겠습니다.
map
- 원본 Observable에서 통지하는 데이터를 원하는 값으로 변환 후 통지합니다.
- 변환 전, 후 타입이 달라도 상관없습니다. (int -> String)
- null을 반환하면 NullpointException이 발생하므로 null이 아닌 데이터 하나를 반드시 반환해야 합니다.

public static void main(String[] args) {
Observable<Integer> numbers = Observable.just(1, 2, 3, 4, 5, 6);
numbers.map(num -> num * 10)
.subscribe(System.out::println);
}
// 출력
10
20
30
40
50
60
flatMap
- 원본 데이터를 원하는 값으로 변환 후 통지하는 map과 같습니다.
- map이 1대 1 변환인 것과 달리 flatMap은 1대다 변환하므로 데이터 한 개로 여러 데이터를 통지할 수 있습니다.
- map은 변환된 데이터를 반환하지만 flatMap은 변환된 여러 개의 데이터를 담고 있는 새로운 Observable을 반환합니다.
- 원본 데이터와 변환된 데이터를 조합해서 새로운 데이터를 통지합니다.
- Observable에 원본 데이터 + 변환된 데이터 = 최종 데이터를 실어서 반환합니다.


public static void main(String[] args) {
Observable.range(2, 1)
.flatMap(
data -> Observable.range(1, 9), (sourceData, newData) // 1차로 변환후
-> sourceData + " * " + newData + " = " + sourceData * newData) // 최종 변환
.subscribe(System.out::println);
}
// 출력
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8
2 * 5 = 10
2 * 6 = 12
2 * 7 = 14
2 * 8 = 16
2 * 9 = 18
concatMap
- flatMap과 마찬가지로 받은 데이터를 변환하여 새로운 Observable로 반환합니다.
- 반환된 새로운 Observable을 하나씩 순서대로 실행하는 것이 FlatMap과 다릅니다.
- 데이터의 처리 순서는 보장하지만 처리 중인 Observable의 처리가 끝나야 다음 Observable이 실행되므로 처리 성능에는 영향을 줄 수 있습니다.

public static void main(String[] args) {
Observable.interval(100L, TimeUnit.MICROSECONDS)
.take(4)
.skip(2)
.concatMap(
num -> Observable.interval(200L, TimeUnit.MICROSECONDS)
.take(10) // 10개만 발행
.skip(1)// 1개를 건너뛰고 2부터 시작
.map(data -> num + " * " + data + " = " + num * data)
).subscribe(
data -> System.out.println(data),
error -> System.out.println("error: " + error),
() -> System.out.println("complete")
);
try {
Thread.sleep(5000L); // main thread 5초간 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 출력
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8
2 * 5 = 10
2 * 6 = 12
2 * 7 = 14
2 * 8 = 16
2 * 9 = 18
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
3 * 4 = 12
3 * 5 = 15
3 * 6 = 18
3 * 7 = 21
3 * 8 = 24
3 * 9 = 27
switchMap
concatMap과 마찬가지로 받은 데이터를 변환하여 새로운 Observable로 반환합니다.
concatMap과 다른 점은 switchMap은 순서를 보장하지만 새로운 데이터가 통지되면 현재 처리 중이던 작업을 바로 중단합니다.

public static void main(String[] args) {
Observable.interval(100L, TimeUnit.MICROSECONDS)
.take(4)
.skip(2) // 0(x) 1(x) 2(o) 3(o)
.switchMap(
num -> Observable.interval(200L, TimeUnit.MICROSECONDS)
.take(10) // 10개만 발행
.skip(1)// 1개를 건너뛰고 2부터 시작(컴퓨터는 0부터 시작)
.map(data -> num + " * " + data + " = " + num * data)
).subscribe(
data -> System.out.println(data),
error -> System.out.println("error: " + error),
() -> System.out.println("complete")
);
try {
Thread.sleep(5000L); // main thread 5초간 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 출력
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
3 * 4 = 12
3 * 5 = 15
3 * 6 = 18
3 * 7 = 21
3 * 8 = 24
3 * 9 = 27
complete
groupBy
- 하나의 Observable을 여러 개의 새로운 GroupedByObservable로 만듭니다.
- 원본 Observable의 데이터를 그룹별로 묶는다기보다는 각각의 데이터들이 그룹에 해당하는 Key를 가지게 됩니다.
- getKey()를 통해 그룹을 구분할 수 있습니다.

public static void main(String[] args) {
Observable<Integer> numbers = Observable.just(1, 2, 3, 4, 5, 6);
numbers.groupBy(num -> num % 2 == 0 ? "짝수" : "홀수")
.subscribe(grouped -> grouped.subscribe(data -> System.out.println("key: " + grouped.getKey() + ", value: " + data)));
}
// 출력
key: 홀수, value: 1
key: 짝수, value: 2
key: 홀수, value: 3
key: 짝수, value: 4
key: 홀수, value: 5
key: 짝수, value: 6
toList
- 통지가 끝났을 때 완료 통지를 하며, 리스트로 통지합니다.

public static void main(String[] args) {
Observable<Integer> numbers = Observable.just(1, 2, 3, 4, 5, 6);
numbers.toList()
.subscribe(System.out::println);
}
// 출력
[1, 2, 3, 4, 5, 6]
toMap
toList와 마찬가지로 완료 통지 후 Map 형태로 통지합니다.
중복되는 key는 있을 수 없으며, 같은 key가 생성되면 덮어씌웁니다.

Observable<Integer> numbers = Observable.just(1, 2, 3, 4, 5, 6);
numbers.toMap(num -> num % 2 == 0 ? "짝수" : "홀수")
.subscribe(System.out::println);
// 출력 - 같은 key면 덮어씌우므로 홀수 / 짝수의 key로 2개의 데이터만 나옵니다.
{홀수=5, 짝수=6}
Map 중에 switchMap이 가장 궁금했는데 이번에 강의를 들으면서 다시 알게 된 것 같습니다.
좀 더 공부하면서 익숙하게 사용하도록 노력하겠습니다.
'RxJava' 카테고리의 다른 글
| [RxJava] 데이터 결합 연산자 (0) | 2025.02.11 |
|---|---|
| [RxJava] RxJava 퀴즈 문제 (0) | 2025.02.09 |
| [RxJava] 데이터 필터링 연산자 (0) | 2025.02.01 |
| [RxJava] 생성 연산자 (0) | 2025.01.30 |
| [RxJava] Single vs Maybe vs Completable (0) | 2025.01.27 |
