You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何按列表特定元素过滤?优化空值处理代码

Kotlin 中服务器数据过滤与转换的地道写法

从服务器拉取的电影数据列表可能为空或null,下面是已经实现的基础空值过滤与转换逻辑:

fun filterMovieItemList(unfilteredList: List<MovieItem>): List<MovieItemModel> {
    val movieItemModelList = mutableListOf<MovieItemModel>()
    if (unfilteredList.isNotEmpty()) {
        unfilteredList.forEachIndexed { _, movieItem ->
            val movieDetails = movieItem.movieDetails
            if (movieDetails != null && !movieDetails.name.isNullOrEmpty()) {
                val icon = movieDetails.iconUrl ?: "xyz"
                movieItemModelList.add(
                    MovieItemModel(
                        movieDetails.name,
                        icon,
                        movieDetails.summary ?: "",
                    )
                )
            }
        }
    }
    return movieItemModelList
}

我尝试用map系列方法优化代码提升可读性,写出了下面的版本,但不确定写法是否正确:

fun filterMapMovieItemList(unfilteredList: List<MovieItem>): List<MovieItemModel> {
    return unfilteredList.mapNotNull { data ->
        data.movieDetails?.name?.let {
            data.movieDetails
        }
    }.map { movieItem ->
        val icon = movieItem.iconUrl ?: "xyz"
        MovieItemModel(
            name = movieItem.name ?: "",
            icon = icon,
            summary = movieItem.summary ?: ""
        )
    }
}

先看你写的优化写法是否正确

这个写法是可行的,但存在可以优化的点:当前代码会遍历两次集合(一次mapNotNull筛选有效数据,一次map转换模型),可以合并为单次遍历提升效率;另外map里的name ?: ""属于冗余判断,因为mapNotNull已经确保name非空。


更地道的Kotlin写法

1. 合并过滤与转换,单次遍历完成

用mapNotNull同时完成条件判断和模型转换,避免多次遍历:

fun filterMovieItemList(unfilteredList: List<MovieItem>): List<MovieItemModel> {
    return unfilteredList.mapNotNull { movieItem ->
        val details = movieItem.movieDetails
        // 筛选出name非空的有效details
        val validName = details?.name.takeIf { !it.isNullOrEmpty() } ?: return@mapNotNull null
        
        val icon = details.iconUrl ?: "xyz"
        MovieItemModel(
            name = validName,
            icon = icon,
            summary = details.summary ?: ""
        )
    }
}

takeIf会在条件满足时返回自身,否则返回null;mapNotNull会自动过滤掉所有null结果,一次遍历完成所有操作。

2. 拆分过滤与转换,逻辑更清晰

如果倾向于把筛选和转换步骤分开,可以用filter+map组合:

fun filterMovieItemList(unfilteredList: List<MovieItem>): List<MovieItemModel> {
    return unfilteredList.filter { item ->
        val details = item.movieDetails
        details != null && !details.name.isNullOrEmpty()
    }.map { item ->
        val details = item.movieDetails!! // 已经通过filter校验,可安全解包
        val icon = details.iconUrl ?: "xyz"
        MovieItemModel(
            name = details.name,
            icon = icon,
            summary = details.summary ?: ""
        )
    }
}

其他适用的方法

除了map系列方法,还可以结合这些Kotlin特性简化代码:

  • 作用域函数(run/let):通过作用域函数减少变量重复引用,让代码更连贯:
fun filterMovieItemList(unfilteredList: List<MovieItem>): List<MovieItemModel> {
    return unfilteredList.mapNotNull { item ->
        item.movieDetails?.run {
            name.takeIf { !it.isNullOrEmpty() }?.let { validName ->
                MovieItemModel(validName, iconUrl ?: "xyz", summary ?: "")
            }
        }
    }
}
  • Sequence序列:如果处理的是超大数据量,用asSequence()转为序列,延迟执行所有操作,减少中间集合的内存开销:
fun filterMovieItemList(unfilteredList: List<MovieItem>): List<MovieItemModel> {
    return unfilteredList.asSequence()
        .mapNotNull { it.movieDetails } // 过滤null的details
        .filter { !it.name.isNullOrEmpty() } // 过滤name为空的项
        .map { details ->
            MovieItemModel(details.name, details.iconUrl ?: "xyz", details.summary ?: "")
        }
        .toList() // 最终转为List
}

序列的操作是懒加载的,只有调用toList()时才会执行所有步骤,适合大数据量场景。

内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 15:13:09