Kotlin特殊高级用法

2017 Google IO大会上 Google以官方身份指定Kotlin成为android官方支持开发语言后,
一时间github上的kt项目如春笋般争先恐后地破土而出。
你还有底气说你依旧坚持java不学Kotlin么?


Kotlin简介

  • 由 JetBrain 的牛人 Dmitry Jemerov 在2011年开始带队开发。
  • 主要是解决Java之前被诟病已久的问题,而且积极借鉴了 Scala、Ruby 等新语言在开发效率和简洁性上的优势。
  • Kotlin程序可以使用所有现有的Java框架和Java libraries。
  • 最重要的是Kotlin相对于java可以少写n多代码,还自带安全检查,避免NullPointerException之类异常出现。
  • 不增加运行时开销,AndroidStudio3.0对Kotlin提供了良好的支持。

triple扩展功能

顾名思义,扩展函数是帮助我们扩展类的功能而不必修改该类代码的函数。

  • 以一个非常简单的例子来理解:

    1
    2
    3
    4
    5
    fun Int.triple(): Int {
    return this * 3
    }
    // 我们可以这样使用
    var result = 3.triple()
  • 另一个例子,我们来看看我们如何在Android View中使用它。

    1
    2
    3
    4
    5
    fun ImageView.loadImage(url: String) {
    Glide.with(context).load(url).into(this)
    }
    // 我们可以这样使用
    imageView.loadImage(url)

    when表达式

    示例一:你可以像switch那样使用when

    1
    2
    3
    4
    5
    when(view.visibility){
    View.VISIBLE -> toast("visible")
    View.INVISIBLE -> toast("invisible")
    else -> toast("gone")
    }

    注:在when中,else同switch的default。
    示例二:无自变量的when

    1
    2
    3
    4
    5
    6
    7
    val res = when {
    x in 1..10 -> "cheap"
    x !in 10..15 -> "x is outside the range"
    s.contains("hello") -> "it's a welcome!"
    v is ViewGroup -> "child count: ${v.getChildCount()}"
    else -> ""
    }

    示例三:android中的应用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
    R.id.home -> consume { navigateToHome() }
    R.id.search -> consume { MenuItemCompat.expandActionView(item) }
    R.id.settings -> consume { navigateToSettings() }
    else -> super.onOptionsItemSelected(item)
    }

    inline fun consume(f: () -> Unit): Boolean {
    f()
    return true
    }

示例四: 自动转型(Auto-casting)

1
2
3
4
5
6
when (view) {
is TextView -> toast(view.text)
is RecyclerView -> toast("Item count = ${view.adapter.itemCount}")
is SearchView -> toast("Current query: ${view.query}")
else -> toast("View type not supported")
}

Kotlin的stdlib提供一些高阶函数

传送地址:Kotlin的stdlib

TODO

代码运行到这会抛未实现的异常,提醒你该方法还未实现!

1
2
3
4
5
fun init(){
TODO("还没有实现!")
}
FATAL EXCEPTION: main
kotlin.NotImplementedError: An operation is not implemented: 还没有实现!

apply

相当于java写法更优雅,代码看着更舒适

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//使用apply
val textView = TextView(this@TestActivity).apply {
textSize = sp(10f).toFloat()
textColor = Color.BLUE
leftDrawable(R.drawable.icon_user,10)
....
}

//等同于下面代码
val textView1 = TextView(this@TestActivity)
with( textView1 ) {
textSize = sp(10f).toFloat()
textColor = Color.BLUE
leftDrawable(R.drawable.icon_user,10)
....
}

//也等同于
val textView1 = TextView(this@TestActivity)
textView1.textSize = sp(10f).toFloat()
textView1.textColor = Color.BLUE
textView1.leftDrawable(R.drawable.icon_user,10)
textView1....

lazy

1
2
3
4
5
6
7
8
fun <T> lazy(initializer: () -> T): Lazy<T> (source)

fun <T> lazy(
mode: LazyThreadSafetyMode,
initializer: () -> T
): Lazy<T> (source)

fun <T> lazy(lock: Any?, initializer: () -> T): Lazy<T> (source)

得到延迟初始化对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//得到lazy对象
val init = lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
TextView(this).apply {
textSize = sp(10f).toFloat()
textColor = Color.BLUE
}
}

//或者 不设置参数
val init = lazy {
TextView(this).apply {
textSize = sp(10f).toFloat()
textColor = Color.BLUE
}
}


//等同于
val init by lazy {
TextView(this).apply {
textSize = sp(10f).toFloat()
textColor = Color.BLUE
}
}

//使用这个lazy<TextView>对象
init.value.gravity = Gravity.CENTER

repeat

1
2
3
4

inline fun repeat(times: Int, action: (Int) -> Unit)

inline fun repeat(times: Int, action: (Int) -> Unit) (source)

执行给定的函数动作指定次数。
将当前迭代的一个索引作为参数传递给动作。

let

1
inline fun <T, R> T.let(block: (T) -> R): R (source)

将指定的函数块调用此值作为参数并返回其结果。
类似Rxjava的map功能

to

1
infix fun <A, B> A.to(that: B): Pair<A, B> (source)

创建一个类型对。

1
2
val map = mapOf(1 to "x", 2 to "y", -1 to "zz")
println(map) // {1=x, 2=y, -1=zz}

run

1
2
3
4
5
inline fun <R> run(block: () -> R): R (source)
//调用指定的函数块并返回其结果。

inline fun <T, R> T.run(block: T.() -> R): R (source)
//将指定的函数块调用此值作为其接收器并返回其结果。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
fun fun_run(){
run({
println("匿名函数")
})
var i:Int = run({
return@run 1//带返回值
//run 是一个函数,函数自动成为标签
})
println("${i}")
i = run outer@{//带自定义标签的方式
return@outer 2//匿名函数可以通过自定义标签进行跳转和返回,可以带返回值
}
}

自定义标签使用示例:

1
2
3
4
5
6
7
loop@ for (i in 1..10) {
for (j in 1..10) {
if (i == 5) {
continue@loop
}
}
}

with

1
2
inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)
//调用指定的函数块作为给定的接收器作为它的接收器,并返回其结果。

示例:

1
2
3
4
5
6
7
val textView1 = TextView(this@TestActivity)
with( textView1 ) {
textSize = sp(10f).toFloat()
textColor = Color.BLUE
leftDrawable(R.drawable.icon_user,10)
....
}

also

1
2
inline fun <T> T.also(block: (T) -> Unit): T (source)
//调用指定的函数块,this其值为其参数并返回this值。