Kotlin Lambda编程

1,242 阅读5分钟

Lambda编程

集合的创建与遍历

使用内置的listOf()函数初始化集合,使用for-in循环来遍历集合。

val list = listOf("apple", "banana", "orange", "pear", "grape")
for (fruit in list) {
    println(fruit)
}

listOf()函数创建的是一个不可变的集合,只能用于读取,无法进行添加、修改或删除操作

List集合

使用listOf()函数初始化不可变集合;

使用mutableListOf()函数创建一个可变集合;

val list1 = listOf("apple", "banana", "orange", "pear")
for (fruit in list1) println(fruit)

val list2 = mutableListOf("apple", "banana", "orange", "pear")
list2.add("watermelon")
for (fruit in list2) println(fruit)

Set集合

Set集合的用法与List集合几乎一模一样,只是将创建集合的方式换成了setOf()mutableSetOf()函数而已。

val set = setOf("apple", "banana", "orange", "pear")
for(fruit in set) println(fruit)

需要注意,Set集合底层使用hash映射机制来存放数据的,因此集合中的元素无法保证有序,这是和List集合最大的不同之处。

Map集合

Map是一种键值对形式的数据结构,因此在用法上和ListSet集合有较大的不同。

传统的Map用法是先创建一个HashMap的实例,然后将一个个键值对数据添加到Map中:

传统写法:
val map = HashMap<String, Int>()
map.put("apple", 1)
map.put("banana", 2)
map.put("orange", 3)
map.put("pear", 3)

但在Kotlin中不建议使用put()get()方法来对Map进行添加和读取数据操作,而是更加推荐一种类似于数组下标的语法结构:

推荐写法:
val map = HashMap<String, Int>()
map["Apple"] = 1
map["banana"] = 2
map["orange"] = 3
map["pear"] = 4

Kotlin中也提供了mapOf()mutableMapOf()函数简化Map的用法

简便写法:
val map = mapOf("apple" to 1, "banana" to 2, "orange" to 3, "pear" to 4)
for ((fruit, number) in map) println("fruit is " + fruit + ",number is " + number)

to是一个infix函数,使用for-in循环遍历map

函数式API语法结构

如何在一个水果集合里找到单词最长的那个水果?

普通写法:
val list = listOf("apple", "banana", "orange", "pear")
var maxLengthFruit = ""
for (fruit in list) {
    if (fruit.length > maxLengthFruit.length) {
        maxLengthFruit = fruit
    }
}
println("max length fruit is " + maxLengthFruit)

函数式API写法:
val list = listOf("apple", "banana", "orange", "pear")
val maxLengthFruit = list.maxBy { it.length }
println("max length fruit is " + maxLengthFruit)

Lambda定义:Lambda就是一小段可以作为参数传递的代码

通常情况下,我们向函数传参时只能传入变量,而借助Lambda却允许传入一小段代码

语法结构:{参数名1:参数类型, 参数名2:参数类型 -> 函数体}

首先最外层是一对大括号,如果有参数传入到Lambda表达式中的话,需要声明参数列表,参数列表的结尾使用一个->符号,表示参数列表的结束以及函数体的开始,函数体中可以编写任意行代码,并且最后一行代码会自动作为Lambda表达式的返回值。

maxBy()函数:接受一个Lambda类型参数(Lambda表达式),并且会在遍历集合时将每次遍历的值作为参数传递给Lambda表达式。maxBy()函数的工作原理是根据我们传入的条件遍历集合,从而找到该条件下的最大值。

  1. 接收Lambda表达式作为参数
val list = listOf("apple", "banana", "orange", "pear")
val newList = list.map({fruit: String -> fruit.toUpperCase()})
for(fruit in newList) println(fruit)
  1. 如果Lambda参数是函数最后一个参数时,可以把Lambda表达式移到函数括号外面
val newList = list.map(){fruit: String -> fruit.toUpperCase()}
  1. 如果Lambda参数是函数唯一一个参数时,可以省略函数的括号
val newList = list.map{fruit: String -> fruit.toUpperCase()}
  1. 基于类型推导机制,Lambda表达式中的次数列表在大多数情况下不必声明参数类型
val newList = list.map{fruit -> fruit.toUpperCase()}
  1. Lambda表达式的参数列表只有一个参数时,不必声明参数名,使用it关键字代替
val newList = list.map{it.toUpperCase()}

常用API

  • map:用于将集合中的每个元素都映射成一个另外的值,映射的规则在Lambda表达式中指定,最终生成一个新的集合
  • filter:用来过滤集合中的数据,可以配合map使用(会保留符合条件的)
  • any:用来判断集合中是否至少存在一个元素满足指定条件
  • all:用来判断集合中是否所有元素都满足指定条件
保留5个字母以内的,再转大写(先过滤再操作)
val newList = list.filter { it.length <= 5 }
        .map { it.toUpperCase() }

any函数表示集合中是否有5个字母以内的单词
all函数表示集合中是否所有单词都在5个单词以内
val anyResult = list.any { it.length <= 5 }
val allResult = list.all { it.length <= 5 }
println("anyResult is " + anyResult + ", allResult is " + allResult)
输出结果:
anyResult is true, allResult is false

java函数式API

如果在Kotlin代码中调用了一个java方法,并且该方法接收一个java单抽象方法接口参数,就可以使用函数时APIjava单抽象方法接口指的是接口中只有一个待实现方法,如果接口中有多个待实现方法,则无法使用函数式API。前提:Kotlin中调用java方法,并且单抽象方法接口也必须式萤java语言定义的。

Runnable接口是一个最为常见的单抽象方法接口,这个接口中只有一个待实现的run()方法。

java写法:
new Thread(new Runnable(){
    @Override
    public void run() {
        System.out.println("Thread is running");
    }
}).start();
Kotlin写法:舍弃new关键字,创建匿名类实例的时候改用object关键字
Thread(object: Runnable{
    override fun run() {
        println("Thread is running")
    }
}).start()

简化:1.因为Runnable类中只有一个待实现方法,不需要显式重写run()方法
Thread(Runnable {
    println("Thread is running")
}).start()

再简化:2.如果一个Java方法的参数列表中不存在一个以上Java单抽象接口方法,可以将接口名省略
Thread({
    println("Thread is running")
}).start()

最简化:3.当Lambda表达式时方法的最后一个参数时,可以将表达式要到方法括号的外。同时,如果Lambda表达式还是方法的唯一一个函数,还可以把方法的括号省略
Thread{
    println("Thread is running")
}.start()