文章目录
- 函数式编程
- DSL
- 扩展函数
函数式编程
举个栗子:forEach
var print = fun (name:String):Unit{
println(name)
}
fun main(args: Array<String>) {
var names = listOf<String>("Tom,Jerry,Lucy")
//forEach接收的参数为一个函数
names.forEach(print)
}
运行结果
forEach接收的参数为一个函数,这个函数叫action,这个函数的作用就是:在集合里遍历,对于每个element都执行这个函数
所以上边的代码等价于
for(element in names){
println(element)
}
forEach就是一个高阶函数,高阶函数就是参数或返回值是函数的函数
刚才的写法是比较麻烦的,简化如下:
var names = listOf<String>("Tom,Jerry,Lucy")
names.forEach{
a -> println(a)
}
forEach后边跟一个大括号,里边是一个匿名函数,参数是a,函数的内容是println(a)
还可以进一步简化,参数默认是it
var names = listOf<String>("Tom,Jerry,Lucy")
names.forEach{
println(it)
}
这样的一段代码,就叫闭包
一段程序代码通常由常量、变量和表达式组成,然后使用一对花括号“{}”来表示闭合,并包裹着这些代码,由这对花括号包裹着的代码块就是一个闭包
传统写法的缺点
现在有一个类Girl,里边存储了同宿舍女生的信息
data class Girl(var name:String,var age:Int,var height:Int,var address:String)
var girls = listOf<Girl>(
Girl("琼琼",27,163,"沧州"),
Girl("嫚嫚",29,160,"廊坊"),
Girl("二帆",30,160,"廊坊"),
Girl("真真",28,168,"福建"),
Girl("富婆",30,158,"贵州")
)
传送门:【Kotlin】data class
现在筛选出廊坊的舍友,写一个测试类HelloWorld
fun main(args: Array<String>) {
var langfangGirl = ArrayList<Girl>()
for(girl in girls){
if(girl.address == "廊坊"){
langfangGirl.add(girl)
}
}
for(girl in langfangGirl){
println("${girl.address} ${girl.age} 的 ${girl.name}")
}
}
当然可以在Girl.kt中写一个方法
......
fun filterByAddress(address:String){
var addressGirls = ArrayList<Girl>()
for(girl in girls){
if(girl.address == address){
addressGirls.add(girl)
}
}
for(girl in addressGirls){
println("${girl.address} ${girl.age} 的 ${girl.name}")
}
}
测试类中可以直接调用了
fun main(args: Array<String>) {
filterByAddress("贵州")
}
现在要通过年龄筛选,所以再增加一个按年龄筛选的方法,筛选出小于某一年龄的舍友
fun filterByAge(age:Int){
var ageGirls = ArrayList<Girl>()
for(girl in girls){
if(girl.age < age){
ageGirls.add(girl)
}
}
for(girl in ageGirls){
println("${girl.address} ${girl.age} 的 ${girl.name}")
}
}
现在又要通过地址和年龄两个筛选条件筛选,所以再增加一个方法
fun filterByAddressAge(address:String,age:Int){
var addressAgeGirls = ArrayList<Girl>()
for(girl in girls){
if((girl.address == address) and (girl.age < age)){
addressAgeGirls.add(girl)
}
}
for(girl in addressAgeGirls){
println("${girl.address} ${girl.age} 的 ${girl.name}")
}
}
通过上边的需求的不断变化,可以发现,几个需求的实现方法基本是复制粘贴,那么怎样让代码更简洁呢,需要了解以下知识了
高阶函数
maxBy、minBy
现在有个需求,找到宿舍中最年长的舍友,如果按照java程序员的思路是这样写的
var maxAge = 0
for(girl in girls){
if(girl.age > maxAge){
maxAge = girl.age
}
}
println("年龄最大的值是${maxAge}")
for(girl in girls){
if(girl.age == maxAge){
println(girl)
}
}
如果是Kotlin程序员,这个需求对于他们来说就太简单了
println(girls.maxBy{it.age})
maxBy方法返回第一个满足指定评判标准的最大值
也可以找到年龄最低的舍友
println(girls.minBy{it.age})
filter
现在筛选年龄<29,身高>165的舍友
println(girls.filter{
(it.age<29) and (it.height > 160)
})
map
println(girls.map{
"${it.name}:${it.age}"
})
any
判断有没有29岁的舍友
println(girls.any{
it.age == 29
})
count
查找年龄<29岁的舍友的数量
println(girls.count{
it.age < 29
})
find
找到第一个符合条件的舍友并返回,例如查找地址为福建的舍友
println(girls.find{
it.address == "福建"
})
groupBy
按照地区进行分组
println(girls.groupBy{
it.address
})
查看运行结果
{沧州=[Girl(name=琼琼, age=27, height=163, address=沧州)],
廊坊=[Girl(name=嫚嫚, age=29, height=160, address=廊坊), Girl(name=二帆, age=30, height=160, address=廊坊)],
福建=[Girl(name=真真, age=28, height=168, address=福建)],
贵州=[Girl(name=富婆, age=30, height=158, address=贵州)]}
查找地区为廊坊的小伙伴,并打印,注意?
,不为空打印
girls.groupBy{
it.address
}.get("廊坊")?.forEach{
println(it)
}
DSL
扩展函数
在Girls.kt中增加一个方法
fun List<Girl>.findAge(age:Int){
filter{
it.age < age
}.forEach{
println(it)
}
}
测试下
fun main(args: Array<String>) {
girls.findAge(28)
}
我们可以用关键字infix
修改方法
infix fun List<Girl>.findAge(age:Int){
filter{
it.age < age
}.forEach{
println(it)
}
}
调用的时候就可以直接空格调用了
girls findAge 28
运行结果是一样的