关于Kotlin中属性非空且非空时创建对象的惯用方式及指定函数的惯用写法问询
关于Kotlin编程惯用写法的解答
1. 属性既不为null也不为空时创建对象的惯用方式
在Kotlin里,我们通常会结合**takeIf和let**(或run)这两个标准库函数来实现这种场景,用链式调用替代嵌套的if判断,代码更简洁且符合函数式风格。
举个例子,假设我们有一个可能为null的字符串属性,只有当它不为null且非空时,才创建一个User对象:
val username: String? = "kotlin_dev" // 惯用写法:仅当username非null且非空时创建User val user = username?.takeIf { it.isNotEmpty() }?.let { User(username = it) }
takeIf { it.isNotEmpty() }:会在lambda条件满足时返回原对象(这里就是非空的字符串),否则返回null;- 接着用
?.let:只有前面的结果不为null时,才执行lambda里的对象创建逻辑; - 最终
user的类型是User?,完美处理了空安全。
如果是多个属性需要判断,也可以把条件合并到takeIf的lambda里,比如:
val name: String? = "Alice" val age: Int? = 25 val user = (name to age) .takeIf { (name, age) -> name?.isNotEmpty() == true && age != null && age > 0 } ?.let { (name, age) -> User(name!!, age!!) }
2. 给定代码的Kotlin惯用写法优化
你提供的代码逻辑是:生成答案列表后,若列表非空则创建并配置QuestionnaireResponseItemComponent对象,否则返回null。我们可以用同样的链式调用思路简化它,去掉冗余的if-else结构:
优化后的惯用写法
fun createAnswerValue(record: Record): QuestionnaireResponseItemComponent? { return createAnswerList(record) .takeIf { it.isNotEmpty() } ?.let { answerList -> QuestionnaireResponseItemComponent().apply { linkId = record.siblingIndexUID answer = answerList } } }
优化点说明:
- 直接对
createAnswerList(record)的结果调用takeIf,判断列表是否非空,省去了单独的list变量(如果不需要复用列表的话); - 用
?.let承接非空的列表,在lambda里完成对象的创建和配置; - 保留了你原本用
apply来配置对象属性的写法——这本身就是Kotlin中初始化对象的惯用方式,非常适合给对象设置多个属性的场景。
如果需要保留list变量(比如有其他逻辑需要用到),也可以写成:
fun createAnswerValue(record: Record): QuestionnaireResponseItemComponent? { val answerList = createAnswerList(record) return answerList.takeIf { it.isNotEmpty() }?.let { QuestionnaireResponseItemComponent().apply { linkId = record.siblingIndexUID answer = answerList } } }
两种写法都符合Kotlin的惯用风格,核心是利用空安全操作符和标准库函数减少嵌套,让代码更流畅易读。
内容的提问来源于stack exchange,提问作者Pubudu Mahesh Meththananda
相关产品推荐
相关产品推荐

