first和firstOrNull
kotlin
val tm = App.app.getSystemService(TELEPHONY_SERVICE) as TelephonyManager
val cellInfos = tm.allCellInfo // getAllCellInfo() 来自 Android 4.2
val isLte: ((CellInfo) -> Boolean) = { cellInfo: CellInfo ->
cellInfo is CellInfoLte // CellInfoLte 来自 Android 4.2
}
val isNr: ((CellInfo) -> Boolean) = { cellInfo: CellInfo ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
cellInfo is CellInfoNr // CellInfoNr 在Android 10
} else {
false
}
}
val cellInfoList = cellInfos?.filter { it.isRegistered && (isLte(it) || isNr(it)) }
if (cellInfoList.isNullOrEmpty()) {
return null
}
// 优先获取5G
val cellInfo: CellInfo = cellInfoList.firstOrNull(isNr) ?: cellInfoList.first(isLte)
如上示例代码,功能为获取Android设备的蜂窝信息,下面代码获取了LTE或NR(即4G或5G)的信息:
kotlin
val cellInfoList = cellInfos?.filter { it.isRegistered && (isLte(it) || isNr(it)) }
if (cellInfoList.isNullOrEmpty()) {
return null
}
如上代码保证了cellInfoList 集合中数据不为空,且数据要么是LTE要么是NR类型的,下面代码优雅的实现了NR(即5G)数据优先使用:
kotlin
val cellInfo: CellInfo = cellInfoList.firstOrNull(isNr) ?: cellInfoList.first(isLte)
firstOrNull允许结果为null,first则不允许结果为null,因为我们确定集合里面最少会有其中一种类型的数据,所以最后可以使用first来获取数据,这是安全的,这样我们终最得到的CellInfo 对象就是绝对不可能为null的对象,所以不用声明为CellInfo? 。
集合中还有一个find函数,它底层是调用的firstOrNull,所以我们尽量使用firstOrNull,不用find,因为firstOrNull功能更显而易见。
集合中还有很多好用的扩展函数,声明在_Collections.kt中,比如:
🧺 一、过滤类(filter)
✅ filter
保留满足条件的元素
val nums = listOf(1, 2, 3, 4, 5)
val evens = nums.filter { it % 2 == 0 }
// [2, 4]
❌ filterNot
过滤掉满足条件的
val evens = nums.filterNot { it % 2 == 0 }
// [1, 3, 5]
👀 filterNotNull
去掉 null
val list = listOf("A", null, "B")
val result = list.filterNotNull()
// ["A", "B"]
🔄 二、映射类(map)
🔁 map
把元素变成另一种形式
val nums = listOf(1, 2, 3)
val squares = nums.map { it * it }
// [1, 4, 9]
🧹 mapNotNull
转换 + 去 null
val list = listOf("1", "a", "3")
val numbers = list.mapNotNull { it.toIntOrNull() }
// [1, 3]
🧵 flatMap
一对多展开
val words = listOf("Hi", "Bye")
val chars = words.flatMap { it.toList() }
// [H, i, B, y, e]
📦 三、查找类
🔍 find / firstOrNull
val nums = listOf(3, 7, 10)
val firstBig = nums.find { it > 5 } // 7
val maybe = nums.firstOrNull { it > 20 } // null
🏁 any / all / none
nums.any { it > 8 } // true
nums.all { it > 0 } // true
nums.none { it < 0 } // true
📊 四、分组 & 统计
🧮 groupBy
按条件分组
val names = listOf("Tom", "Tim", "Lucy")
val grouped = names.groupBy { it.first() }
// {T=[Tom, Tim], L=[Lucy]}
🔢 count
nums.count { it % 2 == 0 } // 偶数个数
📐 五、排序
⬆️ sorted
val nums = listOf(5, 1, 3)
nums.sorted() // [1, 3, 5]
🔽 sortedBy
data class User(val name: String, val age: Int)
val users = listOf(
User("A", 30),
User("B", 20)
)
users.sortedBy { it.age }
🎯 六、取元素
🎯 take / takeLast
nums.take(2) // 前两个
nums.takeLast(2) // 后两个
✂️ drop / dropLast
nums.drop(2) // 去掉前两个
nums.dropLast(1) // 去掉最后一个
🔗 七、集合转换
🧱 toSet() 去重
listOf(1,1,2,2,3).toSet() // [1,2,3]
🗂 associateBy
val usersByName = users.associateBy { it.name }
// Map<String, User>
➕ 八、聚合运算
➕ sumOf
nums.sumOf { it } // 求和
📦 reduce
nums.reduce { acc, i -> acc + i } // 累加
🛟 fold(带初始值)
nums.fold(10) { acc, i -> acc + i } // 从10开始加
🧩 九、拼接 & 字符串
🧵 joinToString
nums.joinToString(", ") // "1, 2, 3"
🧠 十、去重(进阶)
🧼 distinct
listOf(1,2,2,3).distinct() // [1,2,3]
🧬 distinctBy
users.distinctBy { it.age }
🚀 实战味最浓的一行代码组合
val result = users
.filter { it.age > 18 }
.sortedBy { it.age }
.map { it.name }
.joinToString()
👉 过滤 → 排序 → 映射 → 拼接
这就是 Kotlin 集合 API 的精髓链式写法。
🏆 Android 开发中最常用的 Kotlin 集合操作 TOP 15
1️⃣ 接口数据去空 + 防崩
场景: 服务器返回的数据有 null
val validUsers = response.users.filterNotNull()
2️⃣ 过滤无效数据(状态判断)
场景: 只显示"在线设备"
val onlineDevices = devices.filter { it.isOnline }
3️⃣ RecyclerView 列表去重(按ID)
场景: 接口重复数据
val distinctList = list.distinctBy { it.id }
4️⃣ 按时间排序(聊天、日志)
val sorted = messages.sortedByDescending { it.timestamp }
5️⃣ 查找某个元素(是否存在)
val hasError = logs.any { it.level == "ERROR" }
6️⃣ 找到第一个符合条件的数据
val firstUnread = messages.firstOrNull { !it.read }
7️⃣ 列表 → Map(快速查找)
场景: 根据 userId 快速找用户
val userMap = users.associateBy { it.id }
val user = userMap[1001]
8️⃣ Map → List(用于显示)
val userList = userMap.values.toList()
9️⃣ 分组显示(联系人分组)
val grouped = contacts.groupBy { it.name.first().uppercaseChar() }
🔟 统计数量(角标/徽章)
val unreadCount = messages.count { !it.read }
1️⃣1️⃣ 求和(流量、电量、金额)
val total = orders.sumOf { it.price }
1️⃣2️⃣ 扁平化列表(多层数据展开)
场景: 多个文件夹里的文件合并
val allFiles = folders.flatMap { it.files }
1️⃣3️⃣ 安全转换类型(字符串转数字)
val numbers = strings.mapNotNull { it.toIntOrNull() }
1️⃣4️⃣ 取前几个(首页展示)
val top3 = newsList.take(3)
1️⃣5️⃣ 拼接字符串(日志 / 展示)
val names = users.joinToString(", ") { it.name }
🌟 进阶组合写法(面试 & 实战高频)
👉 过滤 + 排序 + 转换 + 展示
val displayText = orders
.filter { it.status == "PAID" }
.sortedByDescending { it.time }
.map { "${it.name} ¥${it.price}" }
.joinToString("\n")
🧠 一张脑图式总结
| 目的 | 常用函数 |
|---|---|
| 过滤数据 | filter filterNotNull |
| 查找判断 | any firstOrNull find |
| 排序 | sortedBy sortedByDescending |
| 去重 | distinctBy |
| 统计 | count sumOf |
| 分组 | groupBy |
| 映射转换 | map mapNotNull |
| 扁平化 | flatMap |
| 截取 | take drop |
| 结构转换 | associateBy toList |
| 拼接显示 | joinToString |
这些基本覆盖了 90% Android 业务代码中的集合操作。