Kotlin里的takeIf和takeUnless

介绍

我们使用kotlin的时候,会经常用到一些如let、apply、run这些作用域函数,它能让我们方便、简洁地链式调用对象的方法,除了这些,Kotlin标准库还提供了 takeIf 函数和 takeUnless 函数. 这些函数允许你在链式调用中加入对象的状态检查。

官方文档在此

使用场景

我们在写if语句的时候经常会遇到这样的场景:前面调用了一个函数计算得出了一个结果,现在需要对这个结果做一个分支判断,并且我们只需要用到if的一个分支时,可以用takeIf和takeUnless代替

如:

    fun testWithoutTakeIf() {
        val name = "yanzhikai"
        val hasYan = name.indexOf("yan")
        Log.i(TAG, "testWithoutTakeIf: hasYan = $hasYan")
        if (hasYan >= 0) {
            Log.i(TAG, "testWithoutTakeIf: has yan")
        }
        Log.i(TAG, "testWithoutTakeIf: $name")
    }
    
输出:
I: testWithoutTakeIf: hasYan = 0
I: testWithoutTakeIf: has yan
I: testWithoutTakeIf: yanzhikai

可以写成:

    fun testTakeIf() {
        val name = "yanzhikai"
        name.indexOf("yan")
            .takeIf {
                Log.i(TAG, "testTakeIf: it = $it")
                it >= 0
            }
            ?.let {
                Log.i(TAG, "testTakeIf: has yan")
            }
        Log.i(TAG, "testTakeIf: $name")
    }
   
输出:
I: testTakeIf: it = 0
I: testTakeIf: has yan
I: testTakeIf: yanzhikai

用法

takeIf
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? 
  • 是扩展函数
  • 上下文对象的引用方式:it
  • 返回值:如果代码块predicate里面返回为true,则返回这个对象本身,否则返回空
  • 使用注意:结果要用?判空
takeUnless
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T?
  • 是扩展函数
  • 上下文对象的引用方式:it
  • 返回值:如果代码块predicate里面返回为false,则返回这个对象本身,否则返回空
  • 使用注意:结果要用?判空
说明

从上面的用法可见它们之间的区别就只有一个是满足代码块里面的条件才返回对象本身,一个是不满足条件才返回,如例子用takeUnless写可以写成:

    fun testTakeUnless() {
        val name = "yanzhikai"
        name.indexOf("yan")
            .takeUnless {
                Log.i(TAG, "testTakeUnless: it = $it")
                it < 0
            }
            ?.let {
                Log.i(TAG, "testTakeUnless: has yan")
            }
        Log.i(TAG, "testTakeUnless: $name")
    }
    
输出:
I: testTakeUnless: it = 0
I: testTakeUnless: has yan
I: testTakeUnless: yanzhikai
优点
  • 可以配合其他作用域函数返回的结果,做出单向判断,保持链式调用

  • 简化写法,逻辑清晰,减少代码量,代码更优雅(可以装逼)。

缺点

在这里插入图片描述

  • 太简洁也是罪,如果返回值和takeXx写在一起时,debug无法进去看到it的值(所以建议比较重要的值可以分行写或者打印出来)

  • 提升代码阅读者的理解难度(毕竟if谁都懂,takeXx要学)

如果需要两个分支?

此时也可以用takeIf和takeUnless,可以加上elvis 操作符来做第二个分支的操作:

        name.indexOf("yan")
            .takeIf {
                Log.i(TAG, "testTakeIf: it = $it")
                it >= 0
            }
            ?.let {
                Log.i(TAG, "testTakeIf: has yan")
            }?: Log.i(TAG, "testTakeIf: no yan")

不过不建议这样做,这样不仅增加了代码理解难度,而且后续维护也比较难(?:后面只能跟一个语句),还不如直接用作用域函数+判断:

        name.indexOf("yan")
            .let {
                Log.i(TAG, "testTakeIf: it = $it")
                if (it >= 0) {
                    Log.i(TAG, "testTakeIf: has yan")
                } else {
                    Log.i(TAG, "testTakeIf: no yan")
                }
            }

以上代码地址

总结

  • takeIf和takeUnless作用:根据代码块里面的返回值,决定返回空还是this本身,配合?.作用域函数来做判断
  • 使用场景:只需要单个if分支语句的时候
  • 优点
    • 可以配合其他作用域函数返回的结果,做出单向判断,保持链式调用
    • 简化写法,逻辑清晰,减少代码量,代码更优雅
  • 缺点
    • 如果返回值和takeXx写在一起时,debug无法进去看到it的值
    • 提升代码阅读者的理解难度

上述意见乃是个人经验之谈,如果错漏,敬请指正

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值