4.2 Kotlin标准库函数


Kotlin提供了一个系统库,是Java库的增强,很多函数适配了Java的类型和方法,同时使用Kotlin的语法,下面我们来研究下广泛使用的函数。

Apply

  • apply 是 Any 的扩展函数, 因而所有类型都能调用。
  • apply 接受一个lambda表达式作为参数,并在apply调用时立即执行,apply返回原来的对象。
  • apply 主要作用是将多个初始化代码链式操作,提高代码可读性。

参考以下实例我们来分析下:

fun main(args: Array<String>) {
    val runnable  = Runnable { 
        print("is running")
    }
    val thread = Thread(runnable)

    thread.isDaemon = true
    thread.start()
}

我们用标准库函数Apply来改写代码:

fun main(args: Array<String>) {
    val runnable = Runnable {
        print("is running")
    }
    Thread(runnable).apply { isDaemon = true }.start()
}

看看代码是不是减少了不少啊,我们创建了一个Runnable实例,然后创建了一个线程运行这个实例,在闭包中我们配置线程实例为一个守护线程。闭包中的代码会在线程实例上运行,并且可以直接在返回值上调用start()方法。

let

let默认当前这个对象作为闭包的it参数,返回值是函数的最后一行或者指定return结果。
let 和 apply 类似, 唯一的不同是返回值,let返回的不是原来的对象,而是闭包里面的值。

fun main(args: Array<String>) {
    println(testLet())
}

fun testLet():Int{
    "Alfred".let {
        println(it)
        println(it.length)
        return 999	//指定返回值为999
    }
}

结果:

Alfred
6
999
fun main(args: Array<String>) {
    val name = "Alfred".let {
        println(it)
        println(it.length)
        "张三" //没指定返回值时,默认返回值为闭包的最后一行
    }

    println(name)
}

结果:

Alfred
6
张三

with

有时候我们在执行对象的多个方法时,必须要写很多次对象名,显得很啰嗦。比如:

class Persion(val name: String, val age: Int, val sex: String) {

    fun showName() {
        println(name)
    }

    fun showAge() {
        println(age)
    }

    fun showSex() {
        println(sex)
    }
}

fun main(args: Array<String>) {
    val persion = Persion("alfred",29,"男")
    persion.showName()
    persion.showSex()
    persion.showAge()
}

执行结果:

alfred
男
29

persion这个实例名是不是重复写了很多遍啊。虽然很整齐啊,但是不推崇。
下面我们使用with来简化下代码:

fun main(args: Array<String>) {
    val persion = Persion("alfred",29,"男")
    with(persion){
        showName()
        showSex()
        showAge()
    }
}

看看是不是相对来说简化了,也挺清晰易懂的。

run

run函数跟apply函数很像,只不过apply返回当前自身对象,而run返回最后一行或指定值,run 就是with与let组合。

fun main(args: Array<String>) {
    val name = "Alfred".run {
        println(this)
        println(this.length)
        "张三" //返回最后一行
    }

    println(name)
    println(testRun()) 
}

fun testRun():String{
    "Alfred".run {
     	return "jack" //指定返回
    }
}

结果:

Alfred
6
张三
jack

lazy

lazy是另一个很有用的函数,可以把非常耗费资源的操作延迟到第一次调用时加载。比如:

fun main(args: Array<String>) {
    val name = lazy {
        for (i in 1..10) {
            print("# ")
        }
        "alfred"
    }

    println(name.value)
    println(name.value)
}

结果:

# # # # # # # # # # alfred
alfred

第一次调用println(name.value)时,才会初始化name,先执行for循环打印10次#,再初始化值为alfred。第二次调用println(name.value)时,name已经赋值为alfred,所以直接打印alfred。
总结: 第一次调用时,lazy 闭包会调用。一般用在单例模式。

use

use与try语句类似,实现了Closeable接口的对象可调用use函数,use函数会自动关闭调用者(无论中间是否出现异常)。下面我们看下源码:

/**
 * Executes the given [block] function on this resource and then closes it down correctly whether an exception
 * is thrown or not.
 *
 * @param block a function to process this [Closeable] resource.
 * @return the result of [block] function invoked on this resource.
 */
@InlineOnly
@RequireKotlin("1.2", versionKind = RequireKotlinVersionKind.COMPILER_VERSION, message = "Requires newer compiler version to be inlined correctly.")
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    var exception: Throwable? = null
    try {
        return block(this)
    } catch (e: Throwable) {
        exception = e
        throw e
    } finally {
        when {
            apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
            this == null -> {}
            exception == null -> close()
            else ->
                try {
                    close()
                } catch (closeException: Throwable) {
                    // cause.addSuppressed(closeException) // ignored here
                }
        }
    }
}

可以看出,use函数内部实现也是通过try-catch-finally块捕捉的方式,所以不用担心会有异常抛出导致程序退出。
close操作在finally里面执行,所以无论是正常结束还是出现异常,都能正确关闭。
看个例子:

fun main(args: Array<String>) {
val io = Files.newInputStream(Paths.get("/data/home/alfred/TestKotlin/.idea/encodings.xml"))
    val info = io.use {
        it.bufferedReader().readLines()
    }
   println(info)
}

结果:

[<?xml version="1.0" encoding="UTF-8"?>, <project version="4">,   <component name="Encoding">,     <file url="PROJECT" charset="UTF-8" />,   </component>, </project>]

use 无论如何都会将 io close, 避免了写复杂的 try-catch-finally 代码。Kotlin的IO流操作变得行云流水。

repeat

顾名思义,repeat 接受函数和整数作为参数,函数会被调用 指定 次,这个函数避免写循环。
还记得lazy初始化那个打印#的例子吗?我们把for循环改写下:

fun main(args: Array<String>) {
    val name = lazy {
        repeat(10) { print("# ") }
        "alfred"
    }

    println(name.value)
    println(name.value)
}

结果:

# # # # # # # # # # alfred
alfred

简单吧!! 语法可有抽象为:

repeat(次数) { 
	重复语句
}

require/assert/check

  • require负责检查输入的参数,如果有问题,抛出IllegalArgumentException
  • check负责检查自身是否万事俱备可以执行了,如果不是,抛出IllegalStateException
  • require + check就是在做前置条件的检查,通过了才可以执行真正的程序逻辑
  • assert负责确保程序执行完毕后的结果/内部状态是否符合预期,如果不是,抛出AssertionError

此处只列出相关知识点,有兴趣的话可以参考如下博客,写得非常详尽。
用好 Require,check,assert,写好 Kotlin 代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alfred Gao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值