1. 概述

本文将介绍如何在 Kotlin 中高效地实现 ListSet 之间的相互转换。

这两种集合类型虽然都继承自 Collection 接口,但在实际开发中经常需要根据业务需求进行转换。幸运的是,Kotlin 标准库提供了丰富的扩展函数,让这类操作变得非常简洁。

我们还会对比不同转换方式的差异,避免在实际项目中踩坑。✅
文中所有示例均通过单元测试验证,代码可直接参考使用。

2. 问题背景

ListSet 都是 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)

这种方式的优点是:

  • ✅ 可明确指定目标类型(如 HashSetLinkedHashSetTreeSet
  • ✅ 生成的集合是 可变的(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可变的,可根据需要替换为 LinkedListArrayDeque 等。

⚠️ 重要提醒:List.equals() 会比较元素值和顺序。由于 HashSet 本身不保证遍历顺序,因此将其转为 List 后,每次运行可能得到不同的元素顺序!

只有基于有序 Set(如 LinkedHashSetTreeSet)转换时,结果才可预期。

4.2 使用扩展函数

推荐使用 toList() 进行转换:

assertThat(inputSet.toList()).isEqualTo(expectedList)

该方法特点如下:

  • ✅ 返回的是 不可变的 ArrayList
  • ✅ 若原 SetLinkedHashSetTreeSet,则顺序会被保留

如需可变列表,使用:

val mutableListOf = inputSet.toMutableList()

📌 对比总结:

方法 返回类型 是否可变 顺序是否确定
toList() List<T> 依赖源 Set 类型
toMutableList() MutableList<T> 同上
ArrayList(set) ArrayList<T> 同上

5. 总结

在 Kotlin 中进行 ListSet 的转换非常方便,主要手段包括:

  • ✅ 利用构造函数:适合需要特定实现类或可变集合的场景
  • ✅ 使用扩展函数:代码更简洁,推荐日常使用
  • ⚠️ 注意返回集合的可变性顺序稳定性

关键要点回顾:

  • toSet() 返回的是不可变 LinkedHashSet
  • toMutableSet() 才能获得可修改的 Set
  • HashSetList 时顺序不可控,生产环境务必留意
  • 善用 toSortedSet() 处理需要排序的去重场景

💡 最佳实践建议:除非有特殊性能或结构要求,优先使用 toSet() / toList() + toMutableXXX() 组合,语义清晰且不易出错。

文中所有示例代码已托管至 GitHub:https://github.com/Baeldung/kotlin-tutorials/tree/master/core-kotlin-modules/core-kotlin-collections-3


原始标题:Convert Between List and Set in Kotlin