카테고리 없음
RxJava에서 merge, zip, combineLatest 차이점과 사용법 총정리
Kyung_Development
2025. 6. 20. 12:23
RxJava를 사용하다 보면 여러 Observable(또는 Single 등)을 조합해서 처리해야 할 때가 많습니다.
그중에서 merge, zip, combineLatest 연산자는 자주 사용되는 조합 연산자입니다.
하지만 각각의 동작 방식과 특성이 달라 어떤 상황에서 어떤 것을 써야 할지 헷갈릴 수 있죠.
이번 글에서는 RxJava의 세 가지 주요 조합 연산자의 차이점과 사용 예, 그리고 언제 쓰면 좋은지 핵심만 딱 정리해드립니다.
1. merge — 여러 스트림을 한데 합쳐서 이벤트를 섞어버린다!
동작 원리
merge는 여러 Observable에서 발생하는 이벤트를 그대로 섞어서 방출합니다.
각 스트림에서 데이터가 나오는 시간 순서대로 섞여 나오며, 순서가 보장되지 않습니다.
특징
- 여러 Observable이 독립적으로 동작하면서 동시에 이벤트를 뿜는 병렬 처리 가능
- 이벤트 순서가 중요하지 않을 때 사용
- 각 스트림 이벤트가 독립적일 때 효과적
언제 쓰는가?
- 여러 API를 동시에 호출해서 응답이 도착하는 대로 처리하고 싶을 때
- 실시간 알림, 로그 스트림 등 이벤트 순서가 중요하지 않은 경우
코드 예시
val obs1 = Observable.just("A", "B", "C").delay(100, TimeUnit.MILLISECONDS)
val obs2 = Observable.just("1", "2", "3").delay(50, TimeUnit.MILLISECONDS)
Observable.merge(obs1, obs2)
.subscribe { println(it) }
// 출력 예시 (순서가 섞임)
// 1
// 2
// 3
// A
// B
// C
2. zip — 같은 순서의 아이템끼리 묶어서 콤보 생성!
동작 원리
zip은 여러 Observable에서 동일 인덱스에 해당하는 아이템을 하나씩 묶어서 하나의 결과를 만들어 내는 연산자입니다.
예를 들어, 첫 번째 Observable의 1번째 아이템과 두 번째 Observable의 1번째 아이템을 묶어서 첫 번째 결과를 방출합니다.
특징
- 아이템 순서와 개수가 매우 중요
- 모든 Observable이 현재 인덱스 아이템을 준비해야 다음 결과가 방출됨 → 동기화 효과
- 병렬로 아이템을 생산할 수 있으나, 결과는 각 인덱스 단위로 직렬 처리되는 느낌
언제 쓰는가?
- 여러 비동기 작업 결과를 한 세트로 묶어서 처리해야 할 때
- 여러 API 호출의 결과를 조합해서 하나의 데이터 객체를 만들 때
코드 예시
val obs1 = Observable.just("A", "B", "C")
val obs2 = Observable.just("1", "2", "3")
Observable.zip(obs1, obs2) { s1, s2 -> "$s1$s2" }
.subscribe { println(it) }
// 출력
// A1
// B2
// C3
3. combineLatest — 각 스트림의 최신 값들을 항상 최신 상태로 조합!
동작 원리
combineLatest는 여러 Observable 중 하나라도 새로운 값을 방출하면,
가장 최근에 방출된 각 Observable의 값을 모아서 새롭게 조합한 결과를 바로 방출합니다.
특징
- 모든 Observable이 최소 1개의 값을 내놓은 뒤부터 작동
- 이벤트가 발생할 때마다 즉시 최신 상태를 반영해서 결과 방출
- 병렬로 동작하며 실시간 최신값 조합에 적합
언제 쓰는가?
- 여러 UI 상태, 실시간 데이터 스트림 등을 조합해서 최신 상태를 반영해야 할 때
- 폼 입력값 여러 개를 실시간으로 조합할 때
- 사용자 입력, 센서 데이터, 여러 상태값이 변할 때마다 합쳐야 하는 경우
코드 예시
val obs1 = Observable.just("A", "B", "C").concatMap { Observable.just(it).delay(100, TimeUnit.MILLISECONDS) }
val obs2 = Observable.just("1", "2", "3").concatMap { Observable.just(it).delay(150, TimeUnit.MILLISECONDS) }
Observable.combineLatest(obs1, obs2) { s1, s2 -> "$s1$s2" }
.subscribe { println(it) }
// 출력 예시 (시간에 따라 다름)
// A1
// B1
// B2
// C2
// C3
RxJava 조합 연산자 비교 정리
연산자 동작 방식 병렬/직렬 주요 특징 사용 시기 대표 예시
merge | 여러 스트림에서 이벤트를 시간순 섞어서 방출 | 병렬 가능 | 순서 보장 X, 이벤트 섞임 | 독립적 이벤트를 순서 상관없이 처리할 때 | 여러 API 응답을 도착하는 대로 처리 |
zip | 같은 인덱스 위치 아이템끼리 묶어서 방출 | 병렬 가능, 결과는 인덱스별 직렬 처리 | 각 스트림의 아이템 개수, 순서 중요 | 동기화된 데이터 세트를 만들어야 할 때 | 여러 API 결과를 하나의 객체로 조합 |
combineLatest | 각 스트림의 최신 값을 실시간 조합 | 병렬 가능 | 이벤트 발생 시 최신 상태를 항상 반영 | 실시간 UI 상태나 여러 상태값 조합 시 | 실시간 사용자 입력값 합치기 |
부가 설명 - Single에서는?
- Single은 한 번만 결과를 내는 타입이라 merge보다는 zip을 더 자주 씁니다.
- 예: 여러 API를 병렬 호출 후 모두 완료되면 결과를 합칠 때 Single.zip() 사용.
마무리
RxJava에서 여러 비동기 작업을 조합할 때,
- 순서와 동기화가 중요하면 zip
- 순서가 필요 없고 이벤트가 흘러들어오는 대로 처리하려면 merge
- 항상 최신 상태를 유지하며 실시간 조합해야 하면 combineLatest
이렇게 이해하시면 훨씬 편하게 상황에 맞는 연산자를 선택할 수 있습니다.
RxJava를 활용한 비동기 프로그래밍, 꼭 마스터하세요! 궁금한 점 있으면 언제든 질문해주세요.