Lambda
run { println(1) }
更常用的为 { 参数 -> 操作 },还可以存储到变量中,把变量作为普通函数对待
val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2))
class Person(val name: String, val age: Int)
val people = listOf(Person("A", 18), Person("B", 19))
println(people.maxBy({ p: Person -> p.age }))
println(people.maxBy() { p: Person -> p.age })
println(people.maxBy { p: Person -> p.age }) //只有一个参数,可省略()
println(people.maxBy() { p -> p.age }) //可推导出类型
println(people.maxBy() { it.age }) //只有一个参数且可推导出类型,会自动生成it
fun printProblemCounts(response: Collection<String>) {
var clientErrors = 0
var serverErrors = 0
response.forEach {
if (it.startsWith("4")) {
clientErrors++
} else if (it.startsWith("5")) {
serverErrors++
}
}
}
成员引用
上面通过Lambda将代码块作为参数传递给函数,若要传递代码块已被封装成函数,则需要传递一个调用该函数的Lambda,如下计算虚岁
class Person(val name: String, val age: Int) {
fun getNominalAge(): Int {
return age + 1
}
}
val people = listOf(Person("A", 18), Person("B", 19))
println(people.maxBy { p: Person -> p.getNominalAge() })
println(people.maxBy(Person::getNominalAge)) //成员引用,可以省略多余的函数调用
上面是系统为fun getNominalAge()自动生成的成员引用,实际定义应该如下,把函数转换为一个值,从而可以传递它
class Person(val name: String, val age: Int) {
val getNominalAge = age + 1
}
val people = listOf(Person("A", 18), Person("B", 19))
println(people.maxBy(Person::getNominalAge))
println(people.maxBy(Person::age))
fun salute() = println("Salute")
run(::salute)
集合的函数式API
filter和map
filter遍历集合并筛选指定Lambda返回true的元素,如下遍历偶数
val list = listOf(1, 2, 3, 4)
println(list.filter { it % 2 == 0 })
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 29), Person("B", 31))
println(people.filter { it.age > 30 })
map对集合中的每一个元素应用给定的函数并把结果收集到一个新的集合
val list = listOf(1, 2, 3, 4)
println(list.map { it * it })
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 29), Person("B", 31))
println(people.map(Person::name))
Lambda会隐藏底层操作,如寻找最大年龄,第一种方式会执行100遍,应该避免
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 29), Person("B", 31))
people.filter { it.age == people.maxBy(Person::age)!!.age }
val maxAge = people.maxBy(Person::age)!!.age
people.filter { it.age == maxAge }
对于Map,可调用filterKeys/mapKeys、filterValues/mapValues
val numbers = mapOf(0 to "zero", 1 to "one")
println(numbers.mapValues { it.value.toUpperCase() })
all、any、count、find
all判断集合所有元素是否都满足条件,any判断至少存在一个满足条件的元素
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 26), Person("B", 27))
val max27 = { p: Person -> p.age >= 27 }
println(people.all(max27))
println(people.any(max27))
!all()表示不是所有符合条件,可用any对条件取反来代替,后者更容易理解
val list = listOf(1, 2, 3)
println(!list.all { it == 3 })
println(list.any { it != 3 })
count用于获取满足条件元素的个数,其通过跟踪匹配元素的数量,不关心元素本身,更加高效,若使用size则会创建临时集合存储所有满足条件的元素
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 26), Person("B", 27))
val max27 = { p: Person -> p.age >= 27 }
println(people.count(max27))
println(people.filter(max27).size)
find找到一个满足条件的元素,若有多个则返回第一个,否则返回null,同义函数firstOrNull
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 26), Person("B", 27))
val max27 = { p: Person -> p.age >= 27 }
println(people.find(max27))
println(people.firstOrNull(max27))
groupby
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 26), Person("B", 27), Person("C", 27))
println(people.groupBy { it.age })
如上打印
{
26=[Person(name=A, age=26)],
27=[Person(name=B, age=27), Person(name=C, age=27)]
}
flatMap、flatten
flatMap根据给定的函数对集合中的每个元素做映射,然后将集合合并,如下打印 [A, 1, B, 2, C, 3]
val strings = listOf("A1", "B2", "C3")
println(strings.flatMap { it.toList() })
如统计图书馆书籍的所有作者,使用Set去除重复元素
data class Book(val title: String, val authors: List<String>)
val books = listOf(
Book("A", listOf("Tom")),
Book("B", listOf("john")),
Book("C", listOf("Tom", "john"))
)
println(books.flatMap { it.authors }.toSet())
flatten用于合并集合,如下打印 [A1, B2, C3]
val strings = listOf("A1", "B2", "C3")
println(listOf(strings).flatten())
序列
序列的好处
map / filter 会创建临时的中间集合,如下就创建了2个
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 26), Person("B", 27))
println(people.map(Person::age).filter { it > 26 })
println(people.asSequence()
.map(Person::age)
.filter { it > 26 }
.toList())
惰性操作及性能
listOf(1, 2, 3, 4).asSequence()
.map { println("map($it)"); it * it }
.filter { println("filter($it)");it % 2 == 0 }
只有当末端操作时才会被调用,如toList()
listOf(1, 2, 3, 4).asSequence()
.map { println("map($it)"); it * it }
.filter { println("filter($it)");it % 2 == 0 }
.toList()
println(listOf(1, 2, 3, 4).asSequence().map { print(" map($it)");it * it }.find { it > 3 })
println(listOf(1, 2, 3, 4).map { print(" map($it)");it * it }.find { it > 3 })
如上都打印4,但序列运行到第二个时已找到满足条件,后面不会再执行
map(1) map(2)4
map(1) map(2) map(3) map(4)4
序列的顺序也会影响性能,第二种方式先filter再map,所执行的变换次数更少
data class Person(val name: String, val age: Int)
val people = listOf(Person("A", 26), Person("AB", 27), Person("ABC", 26), Person("AB", 27))
println(people.asSequence().map(Person::name).filter { it.length < 2 }.toList())
println(people.asSequence().filter { it.name.length < 2 }.map(Person::name).toList())
创建序列
generateSequence根据前一个元素计算下一个元素
val naturalNumbers = generateSequence(0) { it + 1 }
val numbersTo100 = naturalNumbers.takeWhile { it <= 100 }
println(numbersTo100.sum())
和Java一起使用
函数式接口(SAM接口)
若存在如下Java函数
public class Test {
public static void run(int delay, Runnable runnable) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
runnable.run();
}
}
对于上面接受Runnable的接口,可以传递Lambda或创建实例,前者不会创建新的实例,后者每次都会创建
Test.run(1000, Runnable { println("Kotlin") })
Test.run(1000, { println("Kotlin") })
Test.run(1000) { println("Kotlin") } //最优
Test.run(1000, object : Runnable {
override fun run() {
println("Kotlin")
}
})
若Lambda捕捉到了变量,每次调用会创建一个新对象,存储被捕捉变量的值
fun handleRun(msg: String) {
Test.run(1000) { println(msg) }
}
SAM构造方法
大多数情况下,Lambda到函数式接口实例的转换都是自动的,但有时候也需要显示转换,即使用SAM构造方法,其名称和函数式接口一样,接收一个用于函数式接口的Lambda,并返回这个函数式接口的实例
val runnable = Runnable { println("Kotlin") } //SAM
runnable.run()
val listener = View.OnClickListener { view ->
val text = when (view.id) {
1 -> "1"
else -> "-1"
}
println(text)
}
带接收者的Lambda
with
fun alphabet(): String {
val result = StringBuilder()
for (letter in 'A'..'Z') {
result.append(letter)
}
result.append("nover")
return result.toString()
}
上面代码多次重复result这个名称,使用with可以简化,内部可用this调用方法或省略
fun alphabet(): String {
val result = StringBuilder()
return with(result) {
for (letter in 'A'..'Z') {
this.append(letter)
}
append("nover")
toString()
}
}
还可以进一步优化
fun alphabet() = with(StringBuilder()) {
for (letter in 'A'..'Z') {
this.append(letter)
}
append("nover")
toString()
}
apply
with返回的是接收者对象,而不是执行Lambda的结果,而使用apply()会返回接收者对象,可以对任意对象上使用创建对象实例,还能代替Java的Builder
fun alphabet() = StringBuilder().apply {
for (letter in 'A'..'Z') {
this.append(letter)
}
append("nover")
}.toString()
fun alphabet() = buildString {
for (letter in 'A'..'Z') {
this.append(letter)
}
append("nover")
}
原文地址:https://blog.csdn.net/qq_35258036/article/details/134352641
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_3622.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!