Kotlin Academy · Урок

combine и zip: объединение нескольких Flow

Объединяйте несколько Flow и синхронно объединяйте их выдачу с помощью zip.

Урок 3 из 413 шагов

«combine и zip: объединение нескольких Flow» — бесплатный урок Kotlin Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Kotlin Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Kotlin Academy содержит 4 уроков всего.

Зачем объединять потоки?

В реальных приложениях часто требуется объединять несколько потоков данных: настройки пользователя и данные из сети, поля формы и состояние проверки. Kotlin предоставляет для этого zip, combine и merge.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val names = flowOf("Alice", "Bob", "Carol")
    val ages  = flowOf(30, 25, 35)
    names.zip(ages) { name, age -> "$name is $age" }
         .collect { println(it) }
}

zip: попарная выдача значений

zip попарно объединяет значения один к одному и по порядку. Работа прекращается, когда заканчивается более короткий поток.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val a = flowOf(1, 2, 3, 4)   // 4 elements
    val b = flowOf("a", "b", "c")  // 3 elements — zip stops here
    a.zip(b) { n, s -> "$n-$s" }
     .collect { println(it) } // 1-a, 2-b, 3-c
}

Объединение: последние значения

combine выдаёт новое значение при каждой выдаче любого из потоков, используя последнее значение каждого из них. Оба потока должны выдать хотя бы одно значение.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val flow1 = MutableStateFlow(1)
    val flow2 = MutableStateFlow("a")
    combine(flow1, flow2) { n, s -> "$n-$s" }
        .take(1)
        .collect { println(it) } // 1-a
}

Разница между объединением и zip

zip: ожидает соответствующую пару. combine: срабатывает при каждом обновлении, используя последние значения. Используйте объединение для реактивного интерфейса, например для двух полей формы, а zip — для последовательного попарного объединения.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    // zip: 1-a, 2-b
    val nums = flowOf(1, 2).zip(flowOf("a", "b")) { n, s -> "$n-$s" }
    nums.collect { println("zip: $it") }

    // combine fires more:
    combine(flowOf(1, 2), flowOf("a")) { n, s -> "$n-$s" }
        .collect { println("combine: $it") }
}

Объединение потоков без попарного сопоставления

merge выдаёт значения из нескольких потоков по мере их поступления, не объединяя их в пары: порядок выдачи зависит от времени поступления значений.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val a = flow { emit("A1"); delay(50); emit("A2") }
    val b = flow { delay(25); emit("B1") }
    merge(a, b).collect { println(it) } // A1, B1, A2
}

Объединение трёх и более потоков

combine поддерживает несколько потоков. Передайте их как vararg, и лямбда получит все последние значения.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val a = MutableStateFlow("hello")
    val b = MutableStateFlow(42)
    val c = MutableStateFlow(true)
    combine(a, b, c) { s, n, flag -> "$s-$n-$flag" }
        .take(1)
        .collect { println(it) } // hello-42-true
}

flatMapMerge: внутренние потоки выполняются параллельно

flatMapMerge преобразует каждый элемент в поток и собирает все внутренние потоки одновременно, объединяя их результаты.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    (1..3).asFlow()
        .flatMapMerge { n ->
            flow { delay(100L - n * 10); emit("result-$n") }
        }
        .collect { println(it) }
}

flatMapLatest: отмена при новом значении

flatMapLatest отменяет текущий внутренний поток, когда из исходного потока поступает новый элемент. Это идеально подходит для поиска по мере ввода.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    flowOf("k", "ko", "kot", "kotl", "kotli", "kotlin")
        .flatMapLatest { query ->
            flow {
                delay(50)  // simulate debounced search
                emit("Result for: $query")
            }
        }
        .collect { println(it) } // only "Result for: kotlin"
}

zip для попарного сопоставления транзакций

Используйте zip, чтобы сопоставлять события из двух потоков, например действия пользователя с подтверждениями сервера, обеспечивая соответствие один к одному.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val orders = flowOf("Order1", "Order2", "Order3")
    val confirmations = flowOf("Confirmed", "Confirmed", "Rejected")
    orders.zip(confirmations) { order, status -> "$order: $status" }
          .collect { println(it) }
}

Объединение для проверки формы

Объединяйте потоки имени пользователя и пароля, чтобы реактивно вычислять корректность формы: состояние обновляется при изменении любого поля.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
    val username = MutableStateFlow("")
    val password = MutableStateFlow("")
    val isValid = combine(username, password) { u, p ->
        u.length >= 3 && p.length >= 8
    }
    username.value = "alice"
    password.value = "secure123"
    println(isValid.first()) // true
}

onEach + объединение для загрузки из нескольких источников

Объедините признак загрузки с потоком данных, чтобы создать единый объект состояния интерфейса из нескольких независимых источников.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
data class UI(val loading: Boolean, val data: String)
fun main() = runBlocking {
    val loading = MutableStateFlow(true)
    val data    = MutableStateFlow("")
    combine(loading, data) { l, d -> UI(l, d) }
        .take(2)
        .collect { println(it) }
    data.value = "result"
    loading.value = false
}

Быстрая проверка

В чём состоит основное различие между zip и combine?

Итоги

zip последовательно объединяет значения в пары; combine срабатывает при любом обновлении, используя последние значения; merge чередует независимые потоки; flatMapLatest отменяет устаревшие внутренние потоки. Выбирайте подход с учётом необходимости попарного сопоставления или реактивности.

Можно начать бесплатно

Изучай Kotlin с ИИ-репетитором — бесплатно

Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.

Курсы
51
Уроки
203

Часто задаваемые вопросы

Урок «combine и zip: объединение нескольких Flow» бесплатный?

Да — полный текст урока «combine и zip: объединение нескольких Flow» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Kotlin Academy, подпишись на CoddyKit PRO. Курс Kotlin Academy содержит 4 уроков всего.

Чему я научусь в уроке «combine и zip: объединение нескольких Flow»?

Объединяйте несколько Flow и синхронно объединяйте их выдачу с помощью zip. Ты практикуешь Kotlin Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Kotlin Academy?

Предыдущий опыт не требуется. Kotlin Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «combine и zip: объединение нескольких Flow»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Kotlin Academy?

Да. Каждый урок Kotlin Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Операторы Flow: map, filter, transform и take
  2. catch и onCompletion: обработка ошибок в Flow
  3. combine и zip: объединение нескольких Flow
  4. flowOn и buffer: контекст и противодавление
← Назад к Kotlin Academy