Kotlin技巧:利用安全调用(?.)Elvis(?:)运算符 &命名参数和默认参数

安全调用(?.)Elvis(?:)运算符

安全调用(?.)

空引用一直以来都是许多编程语言中开发者的痛点,导致了大量的错误、崩溃和困扰。在Kotlin的核心设计中,通过引入如安全调用(?.)和Elvis(?:)运算符的特性得以缓解。

安全调用运算符允许开发者在可能为空的对象上安全地访问属性或调用方法。如果对象不为空,操作就会被执行;如果对象为空,则跳过操作,并返回null而不是抛出NullPointerException。

在下面的例子中,如果text不为null,那么length将被赋予text的长度;如果text为null,那么length也将为null,全部都不会冒NullPointerException。

val length = text?.length

还可以链式地进行安全调用,如下面的例子:只有在助理、经理和部门都不为空的情况下,才会返回助理的名字。

data class Department(val head: Manager?)
data class Manager(val name: String, val assistant: Assistant?)
data class Assistant(val name: String)

fun getAssistantName(department: Department?): String? {
    // Accesses the name of the assistant of the department head, if all references are non-null
    return department?.head?.assistant?.name
}

Elvis运算符(?:)

此外,Kotlin还引入了Elvis运算符(?:),该运算符提供了一种简明方式来处理在安全调用或任何可为空表达式后的null情况,允许开发者指定一个默认值或替代表达式,以便在前面的表达式评估为null时使用。

在下面的例子中,如果person或person.name为null,那么而不是返回null,而是求值于?:之前的表达式,并将nameLength设为0。

val nameLength = person?.name?.length ?: 0

有许多情景下可以结合两者,以实现更简短、可读且安全的代码库。

他们可以优雅地用在返回语句中,提供默认值,或者简化处理可为空类型的函数中的流程控制。

fun getManagerName(department: Department?): String {
    // Returns the department head's name or "No Manager" if null
    return department?.head?.name ?: "No Manager"
}

或者在可能包含null元素的集合中使用,或者当集合本身可能为null时:

val listOfNames: List<String?> = listOf("Alice", null, "Bob", "Carol")
// Prints the length of each name, skipping nulls
listOfNames.forEach { name ->
    println(name?.length ?: "null")
}

在类型转换时,可以使用安全类型转换运算符(as?),它可以与安全调用运算符结合来安全地尝试类型转换,然后在转换类型上执行操作。

val obj: Any = "This is a string"
// Safely casts obj to a String and then calls length, else returns null if cast fails
val length = (obj as? String)?.length

无论你何时何地使用它们,Kotlin的安全调用运算符(?.)和Elvis运算符(?:)都会简化对null的处理,提高代码的安全性和清晰度。

安全调用运算符通过为null引用返回null来防止NullPointerException,而Elvis运算符在这种情况下提供默认值。两者共同减少了与null相关的错误,并简化了代码,使Kotlin的开发更加高效和直接。

命名和默认参数

在Kotlin中,函数可以有多个参数,记住参数的顺序或者仅靠位置理解他们的作用可能会很具有挑战性,特别是对于接受多个参数或者有相同类型参数的函数。命名参数通过允许开发者指定传递给函数的每个参数的名称来解决这个问题。

例如,有一个用来展示用户信息的函数:

fun displayUserInfo(id: Int, name: String, email: String) {
    println("ID: $id, Name: $name, Email: $email")
}

如果不使用命名参数,需要按照顺序传递参数:

displayUserInfo(1, "Raphael De Lio", "raphael@example.com")

使用命名参数,可以按任意顺序传递参数:

displayUserInfo(id = 1, name = "Raphael De Lio", email = "raphael@example.com")

displayUserInfo(name = "Raphael De Lio", email = "raphael@example.com", id = 1)

另一方面,默认参数允许开发者为函数参数指定默认值。当在函数调用中省略了相应的参数时,这些默认值会被使用。

fun greet(name: String, greeting: String = "Hello") {
    println("$greeting, $name!")
}

这个特性简化了函数的使用,允许调用者省略每个参数,尤其是当大部分会传递常见的值时。

这两个特点同时使用时,会减少对构建者模式的需要,这种模式通常在Java等语言中用来简化构建需要大量参数(其中一些可能是可选的)的对象。

data class User(
    val name: String,
    val age: Int = 0, // 如果未指定,则假定年龄为0
    val email: String = "" // 如果未指定,则假定电子邮件为空字符串
)

然后可以像这样使用它:

val user = User(
    name = "Raphael De Lio",
    age = 30,
    email = "raphael.delio@example.com"
)

在Kotlin中,命名和默认参数改善了函数调用的可读性和灵活性。虽然每个特性单独提供了独特的优点,但结合起来可以让开发者编写更富有表现力和直观的代码。

转自:《Kotlin技巧:利用安全调用(?.)Elvis(?:)运算符 &命名参数和默认参数》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值