1 无参数有返回值
定义无参数有返回值的 Lambda 表达式,只需要将函数体写在 {} 中,函数体可以是表达式或语句块
调用语法格式
{函数体}()
fun main(args: Array<String>) {
{
println("Lambda表达式无参数有返回值")
}()
//Lambda表达式无参数有返回值
2 有参数有返回值
定义有参数有返回值的 Lambda 表达式,需要指定参数名称以及参数类型,参数之间使用英文 , 分割,且参数类型可以省略,函数体会自动校对。Lambda 表达式中的 -> 用于表示箭头,用于指定参数或数据指向。
调用语法格式
{参数名: 参数类型, 参数名: 参数类型 … -> 函数体}(参数1, 参数2, …)
fun main(args: Array<String>) {
val sum = {a : Int, b : Int -> a+b}(6,8)
println("sum=$sum")//14
var sum2 = {a : Int, b : Int -> a+b}
println("sum=" + sum2(6,8))//14
}
Lambda 表达式省略了返回值的类型和方法名,接下来分析是如何声明返回值的类型和返回值?
fun main(args: Array<String>) {
println("-----------------------1------------------------")
val result1 = {
println("输出语句1")
"字符串"}()
println("返回值: $result1")
println("返回值类型: ${result1.javaClass}")
println("-----------------------2------------------------")
val result2 = {
println("输出语句1")
println("输出语句2")
18
}()
println("返回值: $result2")
println("返回值类型: ${result2.javaClass}")
println("-----------------------3------------------------")
val result3 = {
println("输出语句1")
println("输出语句2")
true
}()
println("返回值: $result3")
println("返回值类型: ${result3.javaClass}")
/*-----------------------1------------------------
输出语句1
返回值: 字符串
返回值类型: class java.lang.String
-----------------------2------------------------
输出语句1
输出语句2
返回值: 18
返回值类型: int
-----------------------3------------------------
输出语句1
输出语句2
返回值: true
返回值类型: boolean*/
}
从结果可以得出,在每次调用 Lambda 表达式时,不管方法体里面的语句执行多少条,返回值的类型和值都是由方法体中最后一条语句决定的。
Lambda 表达式作为函数的实际参数或返回值使用时,成为高阶函数
fun IntRange.pickNum(function: (Int) -> Boolean) : List<Int>{
val resultList = mutableListOf<Int>()
for(i in this){ //this 指向定义的区间(IntRange)范围1~20
if(function(i)){ //判断传递过来的Lambda表达式是否满足条件
resultList.add(i) //符合条件的数据添加到集合中
}
}
return resultList
}
fun main(args: Array<String>) {
val list = 1..20
println("---------能被5整除的数-----------")
println(list.pickNum({ x: Int -> x % 5 == 0}))
println("---------能被10整除的数-----------")
println(list.pickNum({ x : Int -> x % 10 == 0}))
/*---------能被5整除的数-----------
[5, 10, 15, 20]
---------能被10整除的数-----------
[10, 20]*/
}
function: (Int) -> Boolean 作为参数,形式参数名 function 可随意修改, 形参类型 Int,
函数返回值 Boolean
1.省略小括号
如果函数只有一个参数,且这个参数类型是一个函数类型,则在调用函数时可以去掉函数名后面的小括号
省略前
list.pickNum({ x: Int -> x % 5 == 0})
省略后
list.pickNum{ x: Int -> x % 5 == 0}
2.将参数移动到小括号外面
如果一个函数有多个参数,但最后一个参数类型是函数类型,则在调用函数时可以将最后一个参数从括号中移除,并去掉参数之间的符号 ,
fun IntRange.pickNum(need: Int, function: (Int) -> Boolean) : List<Int>{
val resultList = mutableListOf<Int>()
for(i in this){
if(function(i)){
resultList.add(i)
}
}
return resultList
}
省略前
list.pickNum(1, { x: Int -> x % 5 == 0})
省略后
list.pickNum(1) { x: Int -> x % 5 == 0}
3.使用 it 关键字
无论函数包含多少个参数,如果其中有参数是函数类型,并且函数类型满足只接收一个参数的要求,可用 it 关键字代替函数的形参及箭头
省略前
list.pickNum{ x: Int -> x % 5 == 0}
省略后
list.pickNum{ it % 5 == 0}
总结:
在 Kotlin 中,从函数定义形式方面来讲,函数可以有普通的定义方式,可以用表达式函数体,可以把 Lambda 赋值给变量,从函数放置的位置来讲,函数可以放置在类的外面(顶层函数)、可以放置在方法的内部(嵌套函数)、可以作为参数传递、可以作为函数的返回值。函数的功能非常强大与灵活,并且地位大大提升。
enum class USER{//声明枚举
NORMAL, VIP
}
fun getPrice(userType : USER) : (Double) -> Double{
if (userType == USER.NORMAL){
return {it}
}
return {price -> 0.88*price}
}
fun main(args: Array<String>) {
val normalUserPrice = getPrice(USER.NORMAL)(200.0)
println("普通用户价格: $normalUserPrice")
val vipPrice = getPrice(USER.VIP)(200.0)
println("超级会员价格: $vipPrice")
/*
普通用户价格: 200.0
超级会员价格: 176.0
*/
}
1.查找元素操作
来看下 Collections 中提供的一些用于查找、匹配集合中元素的方法
方法声明 | 功能描述 |
---|---|
Iterable.find(predicate: (T) -> Boolean): T? | 查找并返回指定条件的第一个元素,没有找到符合条件的元素返回 NULL |
Iterable.first(predicate: (T) -> Boolean): T | 查找并返回指定条件的第一个元素,如果没有找到抛出异常 |
List.last(predicate: (T) -> Boolean): T | 查找并返回指定条件的最后一个元素,如果没有找到抛出异常 |
Iterable.single(predicate: (T) -> Boolean): T | 查找并返回指定条件的元素,并且只能有一个元素,反之抛出异常 |
Iterable.takeWhile(predicate: (T) -> Boolean): List | 查找并返回指定条件的列表,如果没有找到则返回一个空的列表,第一个元素必须满足条件,否则不会继续查找 |
Iterable.filter(predicate: (T) -> Boolean): List | 查找并返回指定条件的列表,如果没有找到则返回一个空的列表,只要满足条件即可 |
Iterable.count(predicate: (T) -> Boolean): Int | 查找(统计)出当前集合中满足指定条件的个数 |
fun main(args: Array<String>) {
val list = listOf(-2, -1, 0, 1, 2)
println("--------find--------")
println("找出大于0的元素: ${list.find{ it > 0 }}")//找出大于0的元素: 1
println("找出等于3的元素: ${list.find{ it == 3 }}")//找出等于3的元素: null
println("--------first--------")
println("大于0的元素: ${list.first{ it > 0 }}")//大于0的元素: 1
println("大于0的元素: ${list.last{ it > 0 }}")//大于0的元素: 2
//println("等于3的元素: ${list.first{ it == 3 }}")//Exception in thread "main" java.util.NoSuchElementException:
// Collection contains no element matching the predicate.
println("大于1的元素: ${list.single{ it > 1 }}")
//println("大于-2的元素: ${list.single{ it > -2 }}")//Exception in thread "main" java.lang.IllegalArgumentException:
// Collection contains more than one matching element.
println("大于-3的元素: ${list.takeWhile{ it > -3 }}")//大于-3的元素: [-2, -1, 0, 1, 2]
println("大于0的元素: ${list.takeWhile{ it > 0 }}")//大于0的元素: [] 必须是第一个元素满足条件才能继续往下查找
println("小于0的元素: ${list.takeWhile{ it < 0 }}")//小于0的元素: [-2, -1]
println("大于-3的元素: ${list.filter{ it > -3 }}")//大于-3的元素: [-2, -1, 0, 1, 2]
println("大于0的元素: ${list.filter{ it > 0 }}")//大于0的元素: [1, 2]
println("小于0的元素: ${list.filter{ it < 0 }}")//小于0的元素: [-2, -1]
val listSuper = listOf(60,80,100,120,140)
println("查找大于100的元素个数: ${listSuper.count{ it > 100}}")//查找大于100的元素个数: 2
println("查找小于60的元素个数: ${listSuper.count{ it < 60}}")//查找小于60的元素个数: 0
}
2.比较元素操作
来看下 Collections 中提供的一些用于比较集合中元素的方法
方法声明 | 功能描述 |
---|---|
Iterable.maxBy(selector: (T) -> R): T? | 查找并返回集合中的最大值 |
Iterable.minBy(selector: (T) -> R): T? | 查找并返回集合中的最小值 |
Iterable.distinctBy(selector: (T) -> K): List | 去除集合中重复的元素 |
fun main(args: Array<String>) {
val list = listOf(-2,0,0,1,1,2)
println("-----------查找最大值------------")
println(list.maxBy { it })//2
println("-----------查找最小值------------")
println(list.minBy { it })//-2
println("-----------集合去重-----------")
println(list.distinctBy { it })//[-2, 0, 1, 2]
}
我们再来看下 Standard 类中的高阶函数
方法声明 | 功能描述 | 适用场景 |
---|---|---|
repeat(times: Int, action: (Int) -> Unit) | 用于重复执行 action() 函数 times 次,其中 times 表示重复执行的次数 | 适用于重复执行一个函数的场景 |
run(block: () -> R): R | run()函数只接收一个 Lambda() 函数为参数,返回值为最后一行语句的值或 return 表达式的值 | 适用于 let() with()的任何场景 |
T.run(block: T.() -> R): R | 调用指定的函数块,用 this 代表函数块中当前的引用对象,并且调用函数块的方法时,this 可省略。该函数的返回值是函数块中的最后一行语句的值或 return 表达式的值 | 适用于 let() with()的任何场景 |
T.let(block: (T) -> R): R | 调用指定的函数块,该函数的返回值是函数块中的最后一行语句的值或 return 表达式的值 | 适用于处理变量不为 null 的场景或确定一个变量的作用域 |
T.apply(block: T.() -> Unit): T | 调用指定的函数块,用 this 代表函数块中当前的引用对象,并且调用函数块的方法时,this 可省略。apply() 函数必须要有返回值,并且返回值是当前的引用对象 | 适用于对实例化对象中的属性进行赋值时,或动态创建一个 View,为该 View 绑定数据时 |
with(receiver: T, block: T.() -> R): R | 将对象作为函数的参数,在函数内可以通过 this 指代该对象。返回值是函数块中的最后一行语句的值或 return 表达式的值 | 适用于调用同一个类的多个方法时,可以省去类名,直接调用类的方法即可 |
fun main(args: Array<String>) {
println("-----------第1个参数为2时------------")
repeat(2, { print("中国")})//中国中国
println("-----------第1个参数为1时------------")
repeat(1){ print("中国")}//中国
println("-----------第1个参数为0时-----------")
repeat(0){ print("中国")}
val list = ArrayList<String>()
list.run {
this.add("土星")
add("天王星")
add("海王星")
}
println(list)//[土星, 天王星, 海王星]
val list2 = ArrayList<String>()
val value = list2.run {
add("金星")
println("集合数据: $list2")
return@run size //结束当前 run 函数,继续执行外部的语句
add("火星")
println("集合数据: $list2")
}
println("返回值是: $value")
println("集合数据: $list2")
/*集合数据: [金星]
返回值是: 1
集合数据: [金星]*/
}
Kotlin 中提供 inline 修饰符,被 inline 修饰的 Lambda (函数) 称为内联函数,使用内联函数可以降低程序的内存消耗。
inline fun <T> check(lock : Lock, body: () -> T) : T{
lock.lock()
try {
return body()
}finally {
lock.unlock()
}
}
fun main(args: Array<String>) {
val ll = ReentrantLock()
check(ll, { print("这是内联函数方法体") })//ll 是一个 Lock对象
}
上面的代码在调用内联函数时,编译器会对 check(ll, { print(“这是内联函数方法体”) }) 进行优化,去掉方法名称以避免入栈出栈操作,直接执行方法体内容。
lock.lock()
try {
return "这是内联函数方法体"
}finally {
lock.unlock()
}
在使用内联函数时,参数也会随之内联,这样会出现一个问题,如果参数有 Lambda 表达式时,Lambda 表达式便不是一个函数的对象,从而也不能作为参数来传递。在此,我们可使用 noinline 修饰符来修饰参数,禁止参数产生内联关系。
inline fun checkT(noinline function: (Int) -> Boolean){
test(function)
}
fun test(function: (Int) -> Boolean){
println("编译通过")
}
fun main(args: Array<String>) {
checkT { x: Int -> x == 2 }//编译通过
}
Kotlin 进阶之路(六) 泛型