1. 概述
本文将介绍如何在 Kotlin 中高效地实现 List
与 Set
之间的相互转换。
这两种集合类型虽然都继承自 Collection
接口,但在实际开发中经常需要根据业务需求进行转换。幸运的是,Kotlin 标准库提供了丰富的扩展函数,让这类操作变得非常简洁。
我们还会对比不同转换方式的差异,避免在实际项目中踩坑。✅
文中所有示例均通过单元测试验证,代码可直接参考使用。
2. 问题背景
List
和 Set
都是 Collection
的子接口,而 Collection
又继承自 Iterable
。Kotlin 在 Iterable
上定义了一系列扩展函数,如 toSet()
、toList()
、toHashSet()
等,极大简化了集合间的转换。
⚠️ 注意:这些扩展函数大多数返回的是不可变集合,如果需要修改结果,请使用对应的
toMutableXXX
方法。
本文重点讨论以下内容:
- 如何将
List
转为Set
- 如何将
Set
转为List
- 不同转换方法的区别与适用场景
测试验证采用主流断言库(如 AssertJ),确保逻辑正确性。
3. 将 List 转换为 Set
3.1 使用构造函数
最直接的方式是调用具体 Set
实现类的构造函数:
val inputList = listOf("one", "two", "three", "four", "one", "three", "five")
val expectedSet = setOf("one", "two", "three", "four", "five")
assertThat(HashSet(inputList))
.isInstanceOf(HashSet::class.java)
.isEqualTo(expectedSet)
这种方式的优点是:
- ✅ 可明确指定目标类型(如
HashSet
、LinkedHashSet
、TreeSet
) - ✅ 生成的集合是 可变的(mutable)
例如,若需保持插入顺序,可用 LinkedHashSet(inputList)
;若需排序,可用 TreeSet(inputList)
。
3.2 使用 Kotlin 扩展函数
更常见的做法是使用标准库提供的扩展函数:
assertThat(inputList.toSet())
.isInstanceOf(LinkedHashSet::class.java)
.isEqualTo(expectedSet)
⚠️ 注意:尽管方法叫 toSet()
,但其底层实现返回的是一个 不可变的 LinkedHashSet
实例。
这意味着:
- ❌ 不能添加或删除元素
- ✅ 保留原始
List
的元素顺序(去重后)
如果需要可变的 Set
,应使用:
val mutableSet = inputList.toMutableSet() // 返回 MutableSet<out String>
此外,还有几个专用转换方法:
方法 | 返回类型 | 是否可变 | 特点 |
---|---|---|---|
toSet() |
Set<T> |
❌ | 内部为 LinkedHashSet ,保留顺序 |
toMutableSet() |
MutableSet<T> |
✅ | 可修改 |
toHashSet() |
HashSet<T> |
✅ | 不保证顺序 |
toSortedSet() |
SortedSet<T> |
✅ | 自动按自然顺序排序 |
📌 小贴士:toSortedSet()
要求元素实现 Comparable
,否则运行时会抛异常。
4. 将 Set 转换为 List
4.1 使用构造函数
同样可以通过构造函数完成转换:
val inputSet = setOf("one", "two", "three", "four", "five")
val expectedList = listOf("one", "two", "three", "four", "five")
assertThat(ArrayList(inputSet)).isEqualTo(expectedList)
此方式生成的 ArrayList
是 可变的,可根据需要替换为 LinkedList
或 ArrayDeque
等。
⚠️ 重要提醒:List.equals()
会比较元素值和顺序。由于 HashSet
本身不保证遍历顺序,因此将其转为 List
后,每次运行可能得到不同的元素顺序!
只有基于有序 Set
(如 LinkedHashSet
、TreeSet
)转换时,结果才可预期。
4.2 使用扩展函数
推荐使用 toList()
进行转换:
assertThat(inputSet.toList()).isEqualTo(expectedList)
该方法特点如下:
- ✅ 返回的是 不可变的
ArrayList
- ✅ 若原
Set
是LinkedHashSet
或TreeSet
,则顺序会被保留
如需可变列表,使用:
val mutableListOf = inputSet.toMutableList()
📌 对比总结:
方法 | 返回类型 | 是否可变 | 顺序是否确定 |
---|---|---|---|
toList() |
List<T> |
❌ | 依赖源 Set 类型 |
toMutableList() |
MutableList<T> |
✅ | 同上 |
ArrayList(set) |
ArrayList<T> |
✅ | 同上 |
5. 总结
在 Kotlin 中进行 List
与 Set
的转换非常方便,主要手段包括:
- ✅ 利用构造函数:适合需要特定实现类或可变集合的场景
- ✅ 使用扩展函数:代码更简洁,推荐日常使用
- ⚠️ 注意返回集合的可变性与顺序稳定性
关键要点回顾:
toSet()
返回的是不可变LinkedHashSet
toMutableSet()
才能获得可修改的Set
HashSet
转List
时顺序不可控,生产环境务必留意- 善用
toSortedSet()
处理需要排序的去重场景
💡 最佳实践建议:除非有特殊性能或结构要求,优先使用
toSet()
/toList()
+toMutableXXX()
组合,语义清晰且不易出错。
文中所有示例代码已托管至 GitHub:https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-collections-3