引言:为什么 Kotlin 遗留代码重构不仅仅是重写
处理 Kotlin 中的遗留代码(legacy code)不仅仅是机械地将 Java 结构替换为语言语法。这是一个战略过程,旨在提高代码的可读性、安全性和性能,同时不改变其外部行为。在本文中,我们将探讨高级重构技术,帮助您将混乱的“动物园”类转变为结构清晰、易于维护的系统。我们不会涉及诸如 var vs val 之类的基础知识——我们将专注于真正改变架构的内容。
1. Java 迁移:替换 getter、setter 和工具类
遗留代码中最常见的问题是大量带有显式 getter 和 setter 的 Java 类,以及静态工具类。Kotlin 提供了优雅的解决方案。
1.1. 基于属性的访问替代 Java Bean
与其编写 user.getName() 和 user.setName("Alice"),不如使用 Kotlin 的属性。这不仅仅是语法糖:您将获得一个可以重写的统一访问接口。
// Java 遗留代码public class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}
// Kotlin 重构后data class User(val name: String) // 如果需要可变性,也可以使用 var如果 getter/setter 逻辑更复杂(例如验证),请使用自定义访问器:
class User { var name: String = "" set(value) { field = value.trim() // 自动去除空格 }}1.2. 扩展函数替代静态工具类
遗留代码通常包含诸如 StringUtils 或 FileUtils 之类的类。在 Kotlin 中,它们被扩展函数所取代。这使代码更具可读性,并更接近“对象方法”的风格。
// Java: StringUtils.isNullOrEmpty(str)// Kotlin: str.isNullOrEmpty()(已存在于 stdlib 中)
// 自定义扩展的示例fun String.isValidEmail(): Boolean { return this.contains("@") && this.contains(".")}
// 使用val email = "user@example.com"if (email.isValidEmail()) { ... }2. 空安全处理:替换 Optional 和空值检查
遗留 Java 代码经常遭受 NullPointerException 的困扰。Kotlin 在类型层面解决了这个问题,但在重构时,需要小心地替换 Optional 和空值检查链。
2.1. 用可空类型替换 Optional
使用 String? 代替 Optional<String>。这降低了创建对象的开销,并使代码更简洁。
// Javapublic Optional<String> findName() { ... }
// Kotlinfun findName(): String? { ... }对于调用链,使用 ?. 运算符和 Elvis 运算符 ?::
// 替代 if (user != null && user.address != null) ...val city = user?.address?.city ?: "Unknown"2.2. 使用 require() 和 check() 处理不变量
在函数开头,使用内置函数替代手动检查:
fun processUser(user: User?) { requireNotNull(user) { "User must not be null" } // 或 require(user != null) { ... } // 后续对 user 的操作(智能转换)}3. 条件逻辑重构:sealed 类和 when
庞大的 if-else 或 switch 代码块是遗留代码的标志。在 Kotlin 中,它们可以被 sealed class 和详尽的 when 所取代。
3.1. 用 sealed class 替换带字段的 enum
如果您有一个为每个值存储不同类型数据的枚举