Java 如何改为Kotlin(二)
针对集合的操作
Kotlin 提供各类集合转换,通过扩充 Java Collections API 的功能,加快开发速度并提升安全性。
map 函数
该函数会返回一个新列表,包含对原数组中每个元素调用指定转换函数后的结果。这样,我们就不必手动创建新列表并对用户列表进行迭代,而可以使用 map
函数,并替换 map
内部 for 循环中的逻辑. 例如:
val formatUserNames: List<String>
get() {
return users!!.map { user ->
val name = if (user.lastName != null) {
if (user.firstName != null) {
"${user.firstName} ${user.lastName}"
} else {
user.lastName ?: "Unknown"
}
} else {
user.firstName ?: "Unknown"
}
name
}
}
为进一步简化,我们还可完全移除 name
变量
val formatUserNames: List<String>
get() {
return users!!.map { user ->
if (user.lastName != null) {
if (user.firstName != null) {
"${user.firstName} ${user.lastName}"
} else {
user.lastName ?: "Unknown"
}
} else {
user.firstName ?: "Unknown"
}
}
}
属性和支持属性
示例:
Repository
类中存在可变的用户列表,该列表会在函数 getUsers
中公开,而该函数则由 Java 代码生成,具体如下:
fun getUsers(): List<User>? { return users }
但此处存在一个问题:由于返回 users
,Repository 类的任何使用者都能够修改用户列表,这并不是一种明智的做法!下面我们将使用支持属性解决这一问题。
首先,将 users
重命名为 _users
。然后添加公用的不可变属性,使其返回用户列表。将其命名为 users
,具体如下:
private val _users = mutableListOf<User>()
val users:List<User>
get() = _users
进行此项更改后,私有 _users
属性将变为公用 users
属性的支持属性。在 Repository
类外部,由于该数据类的使用者只能通过 users
来访问 _users
列表,因此该列表不可变,也不可以在外部调用其add方法,如
Repositoryk.getUsers().add(...) // 该方法不可以调用
顶层函数与扩展函数及其各自属性
Kotlin 支持在任何类、对象或接口的外部声明函数和属性。例如,用于创建新 List
实例的 mutableListOf()
函数便直接在标准库内的 Collections.kt
中定义
在 Java 中,每当需要一些实用程序功能时,您大都会创建一个 Util
类,并将该功能声明为静态函数。而在 Kotlin 中,您可以声明顶层函数,无需使用类。不过,Kotlin 还支持创建扩展函数。这些函数可扩展特定类型,但在该类型外部声明。因此,它们与该类型具有亲和性
当我们缺少某个类的所有权,或由于某个类不允许继承时,我们均需扩展该类的功能。为此,Kotlin 已创建名为扩展的特殊声明。Kotlin 支持扩展函数和扩展属性。
您可使用可见性修饰符来限制扩展函数及扩展属性的可见性。这些修饰符仅向需要扩展的类开放扩展功能,且不会污染命名空间。
对于 User
类,我们可以添加一个扩展函数以计算格式化名称,或将格式化名称存放于扩展属性中。我们可以在 Repository
类的外部但位于同一文件中添加该扩展函数,具体如下:
// extension function
fun User.getFormattedName(): String {
return if (lastName != null) {
if (firstName != null) {
"$firstName $lastName"
} else {
lastName ?: "Unknown"
}
} else {
firstName ?: "Unknown"
}
}
// extension property
val User.userFormattedName: String
get() {
return if (lastName != null) {
if (firstName != null) {
"$firstName $lastName"
} else {
lastName ?: "Unknown"
}
} else {
firstName ?: "Unknown"
}
}
// usage:
val user = User(...)
val name = user.getFormattedName()
val formattedName = user.userFormattedName
然后,我们便可使用这些扩展函数和扩展属性,就如同它们是 User
类的组成部分一般
由于格式化名称是 User
的一个属性,而非 Repository
类的某项功能,因此我们应该扩展属性。Repository
文件内容现如下所示:
val User.formattedName: String
get() {
return if (lastName != null) {
if (firstName != null) {
"$firstName $lastName"
} else {
lastName ?: "Unknown"
}
} else {
firstName ?: "Unknown"
}
}
object Repository {
private val _users = mutableListOf<User>()
val users: List<User>
get() = _users
val formattedUserNames: List<String>
get() {
return _users.map { user -> user.formattedName }
}
init {
val user1 = User("Jane", "")
val user2 = User("John", null)
val user3 = User("Anne", "Doe")
_users.add(user1)
_users.add(user2)
_users.add(user3)
}
}
Kotlin 标准库使用扩展函数来扩展多个 Java API 的功能;Iterable
和 Collection
上的许多功能则以扩展函数的形式实现。例如,我们在上一步使用的 map
函数即为 Iterable
上的扩展函数
作用域函数:let、apply、with、run、also
为了仅在特定对象的上下文中执行代码,而无需根据名称来访问该对象,Kotlin 专门创建了 5 个作用域函数,即:let
、apply
、with
、run
和 also
。这些函数虽简洁但功能强大,它们均具有接收器 (this
),可以带有参数 (it
),还有可能返回值。您可根据自己想要实现的目标,以决定使用哪个函数。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D4b8l8XQ-1602485944287)(C:\Users\Administrator\Pictures\作用域函数.png)]
由于要在 Repository
中配置 _users
对象,我们可以使用 apply
函数,让代码更加符合使用习惯,具体如下:
init {
val user1 = User("Jane", "")
val user2 = User("John", null)
val user3 = User("Anne", "Doe")
_users.apply {
// this == _users
add(user1)
add(user2)
add(user3)
}
}
您可在官方文档中阅读有关作用域函数的更多内容
进一步优化Repository类,即直接在声明中通过用户对 _users
列表进行实例化,从而免于使用 init
块,具体如下:
private val users = mutableListOf(User("Jane", ""), User("John", null), User("Anne", "Doe"))
最后的文件如下:
User.kt
class User(var firstName: String?, var lastName: String?)
Repository.kt
val User.formattedName: String
get() {
return if (lastName != null) {
if (firstName != null) {
"$firstName $lastName"
} else {
lastName ?: "Unknown"
}
} else {
firstName ?: "Unknown"
}
}
object Repository {
private val _users = mutableListOf(User("Jane", ""), User("John", null), User("Anne", "Doe"))
val users: List<User>
get() = users
val formattedUserNames: List<String>
get() {
_users.map { user -> user.formattedName }
}
}
以下是 Java 功能及对应至 Kotlin 的概要:
Java | Kotlin |
---|---|
final 对象 | val 对象 |
equals() | == |
== | === |
仅存放数据的类 | data 类 |
构造函数中的初始化 | init 块中的初始化 |
static 字段和函数 | 在 companion object 中声明的字段和函数 |
单一实例类 | object |