Kotlin之lambda表达式

2018-05-28  本文已影响0人  有没有口罩给我一个

lambda表达式也称λ 表达式,本质上就是可以传递给其他函数的一小段代码。

class Button() {
    fun setOnClickListener(onClickListener: (OnClickListener) -> Unit) {
      }
}

val button = Button()
button.setOnClickListener {
         .........事件触发回调
}

上述Button中setOnClickListener方法接收一个 (OnClickListener) -> Unit
lambda表达式,即:函数的参数是一个lambda表达式类型,这就是Kotlin,当然阔以使用匿名内部类:

view.onClickListener = object :  OnClickListener {
    override fun onClick(view: View) {
    }
}

这不是本节的内容,开始放大招了:结合Lambda+集合,最常用就是使用Lambda操作集合:

//构造几个Person
data class Person(val name: String, val age: Int)
val persons: ArrayList<Person> = ArrayList()
for (count in 0..10) {
    persons.add(Person("name$count", count + 2))
}

persons.filter { it -> it.age % 3 == 0 }.map(Persion::name).forEach(::println)

看看这段代码,filter:就是过滤不满足it.age % 3 == 0 条件的元素,返回List<Person>,map:变换,最后返回List<String>;
看一些filter方法的源码:

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {
        .....
}

看函数的参数:predicate: (T) -> Boolean,Lambda表达式,解析一下,T:泛型,从Iterable<T> ,在这个例子T就是就是Person ,返回值是Boolean,就是例子中的it.age % 3 == 0的结果,这些只是Lambda表达式的返回值,函数返回是一个列表List<T>,集合的变换中间会产生一个新的集合,在上几个操作集合常用的栗子?

//过滤
persons.filter { it -> it.age % 3 == 0 }.map(Persion::name).forEach(::println)
//List<Person>  -> List<String> -> println
persons.map(Persion::name).forEach(::println)
//List<Person> -> maxPerson - println
persons.maxBy(Persion::age).run(::println)
//List<Person> -> sumAge -> println
persons.sumBy(Persion::age).let(::println)

 println(persons.all { it.age > 10 })//匹配所有
println(persons.any { it.age > 12 })//至少匹配一个
println(persons.count { it.age > 12 })//满足该条件的元素个数
println(persons.firstOrNull { it.age > 10 }?.name)//返回第一个或者返回null


println(persons.groupBy { it.age })//按年龄分组 ,返回一个map:key = it.age,value=Person


val books = ArrayList<Book>()
for (index in 0..10) {
    books.add(Book("book$index", listOf("author$index", "author2$index")))
}

books.flatMap { it.authors }.toList().forEach(::println)

val strings = listOf("abc", "def")
println(strings.flatMap { it.toList() })//

我刚刚在上面提了一下,这些操作中间会产生临时列表:

 persons.filter { it -> it.age % 3 == 0 }.map(Persion::name)

filter和map都会返回一个列表,即:上面的链式调用会创建两个列表,数据少还好,要是百万级的,那就jj,怕不怕?反正我是怕了,有没有解决方案呢?答案是肯定滴,该序列上场了。

 //序列
persons.asSequence().map(Persion::name).filter { it.startsWith("A") }.toList()

Sequence 好像是Kotlin中惰性集合的入口,序列不需要创建中间列表来保存中间产生的数据。

Sequence 是什么?

就是一个可以逐个列举元素的元素序列

执行序列操作:中间和末端操作

序列操作分为两类:中间和末端操作,一次中间操作返回的是另一个序列,一次末端操作返回的是一个结果:

   persons.asSequence().map(Persion::name).filter { it.startsWith("A") }.toList()

map和filter是中间的操作,toList()为末端操作,中间操作始终都是惰性的

persons.asSequence().map(Persion::name).filter { 
    println(it)
  it.startsWith("A")
}

println(it)始终不会被执行(末端操作没有被调用;

persons.asSequence().map(Persion::name).filter { 
    println(it)
  it.startsWith("A")
}.toList()

Sequence 和 列表的区别:列表会先把原始的列表变换成另一个列表,然后在从新列表中find,而Sequence 所有的操作是按顺序应用在每一个元素张,处理完第一个元素(先map在find),然后完成接着第二个元素的处理,find方法是返回的是第一个匹配元素。

val listOf = listOf(1, 2, 3, 4)
val map = listOf.map {
    println(it)
    it + 5
}.find {
    println(it)
    it > 3
}

listOf.asSequence().map {
    println(it)
    it + 5
}.find {
    println(it)
    it > 3
}
第一段结果是:1   2  3  4  6
第二段结果:1   6

很明显Sequence find的次数少于列表,性能优于列表,记住了老铁。

如何创建Sequence?

前面的栗子都是使用同一个方法创建Sequence :在集合上调用asSequence(),现在来说一下generateSequence函数。

val takeWhile = generateSequence(0) {
    println(it)
    it + 1
}.takeWhile { it <= 100 }
println(takeWhile.sum())

 File("hello.txt").isHideden().let(::println)
fun File.isHideden() = generateSequence(this) {
          it.parentFile
    }.any {
          it.isFile
}

Kotlin提供其他Lambda表达式相关的库函数
学习Kotlin看官方文档很权威

上一篇 下一篇

猜你喜欢

热点阅读