Kotlin遗留代码重构:逐步指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

在 Kotlin 中重构遗留代码:策略与实践示例



处理遗留代码是每位开发者职业生涯中不可避免的一部分。通常,这类代码是用 Java 编写的,但在迁移到 Kotlin 时并未进行深入重构,或者表现为工具函数和可空字段的"意大利面条式代码"。重构此类代码不仅能提高可读性,还能提升应用性能与安全性。在本文中,我们将通过真实示例,分解在 Kotlin 中重构遗留代码的逐步策略。



1. 准备与测试:安全的基石



在修改代码之前,必须确保修改后代码的正确运行。没有测试,重构就变成了瞎猜。



  • 编写表征测试:使用不同的输入数据运行现有代码,并记录输出值。这些测试将成为你的"安全网"。
  • 使用 @Deprecated 注解:如果你无法立即移除旧的公共 API,请将其标记为 @Deprecated,并指明替代方案。
  • 小步迭代:切勿一次性重构超过一个逻辑模块。每次提交都必须通过所有测试。


针对旧函数的表征测试示例:



// Legacy codefun calculateTotal(items: List<Int>?): Int {    if (items == null) return 0    var sum = 0    for (item in items) {        sum += item    }    return sum}

// Test@Testfun `calculateTotal returns sum or zero`() { assertEquals(0, calculateTotal(null)) assertEquals(6, calculateTotal(listOf(1, 2, 3))) assertEquals(0, calculateTotal(emptyList()))}


2. 消除空安全并使用作用域函数



遗留代码常常因过多的空值检查而备受困扰。Kotlin 提供了优雅的工具来处理可空类型。



我们的做法:将嵌套的 if (x != null) 替换为 let、run 或 also。



// Before refactoringfun processUser(user: User?) {    if (user != null) {        if (user.name != null) {            println("User: ${user.name}")        }    }}

// After refactoringfun processUser(user: User?) { user?.let { u -> u.name?.let { name -> println("User: $name") } }}

// Or even shorter using runfun processUserShort(user: User?) { user?.run { name?.let { println("User: $it") } }}


这种方法使代码更具声明性,并减少了遗漏检查的可能性。



3. 用扩展函数替换工具类



在遗留的 Java 项目中,经常可以看到静态工具类(StringUtils、DateUtils)。在 Kotlin 中,最好用扩展函数来替代它们。



为什么这很重要:扩展函数使代码更易读,并且允许 IDE 将其作为类自身的方法进行提示。



// Legacy Java-styleobject StringUtils {    fun isPalindrome(input: String): Boolean {        val cleaned = input.filter { it.isLetterOrDigit() }.lowercase()        return cleaned == cleaned.reversed()    }}

// Usageval result = StringUtils.isPalindrome("A man, a plan, a canal: Panama")

// Refactoring to Kotlinfun String.isPalindrome(): Boolean { val cleaned = this.filter { it.isLetterOrDigit() }.lowercase() return cleaned == cleaned.reversed()}

// Usageval result = "A man, a plan, a canal: Panama".isPalindrome()


同样值得关注的是,将 java.util.Date 替换为 java.time(LocalDate、Instant)——这将改善时间处理的安全性。



4. 优化

博客

书籍推荐