본문 바로가기

RxJava

[RxJava] 데이터 변환 연산자

안녕하세요. 메로나입니다.

 

오늘은 데이터 변환 연산자에 대해 공부하겠습니다.

 

map
  • 원본 Observable에서 통지하는 데이터를 원하는 값으로 변환 후 통지합니다.
  • 변환 전, 후 타입이 달라도 상관없습니다. (int -> String)
  • null을 반환하면 NullpointException이 발생하므로 null이 아닌 데이터 하나를 반드시 반환해야 합니다.

map 마블다이어그림 참조

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에 원본 데이터 + 변환된 데이터 = 최종 데이터를 실어서 반환합니다.

flatMap 마블다이어그램 참조

 

flatMap 마블다이어그램 참조

 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이 실행되므로 처리 성능에는 영향을 줄  수 있습니다.

concatMap 마블다이어그램 참조

 

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은 순서를 보장하지만 새로운 데이터가 통지되면 현재 처리 중이던 작업을 바로 중단합니다.

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()를 통해 그룹을 구분할 수 있습니다.

groupBy-구글

 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
  • 통지가 끝났을 때 완료 통지를 하며, 리스트로 통지합니다.

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가 생성되면 덮어씌웁니다.

toMap - 구글

 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