Kotlin学习笔记(三)--Lambda编程

文章目录

        • 1. 集合的创建和遍历
        • 2. 集合的函数式API
        • 3. Java函数式API的使用

1. 集合的创建和遍历

集合的函数式API是用来入门Lambda编程的绝佳示例。所以下面我们先通过一个简单的列子来学一下kotlin中的集合。
需求:创建一个包含许多水果名称的集合。
传统写法:

	val list = ArrayList<String>()
    list.add("apple")
    list.add("orange")
    list.add("grape")
    list.add("pear")
    list.add("banana")

观察上述代码是不是觉得每次都要调list.add()有点重复啰嗦不够简洁呢,像这种明确知道在初始化阶段就要赋值的行为能不能简化呢,比如就像初始化数组一样,可以在创建的时候直接赋值,这个问题kotlin懂你,下面我们来看看kotlin简化版。

便捷写法:

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

( listOf()是Kotlin专门提供的一个内置函数,用来简化初始化集合的写法。for-in循环不仅可以用来遍历区间,还可以用来遍历集合 )

两种写法简洁性高下立判,不过需要注意的是:listOf()函数创建的是一个不可变集合,只能读取,不能进行增、删、改操作。那如果我们既要使用这种便捷的初始化操作,又要创建的集合可变怎么办呢?可以使用mutableListOf()函数

val list = mutableListOf("apple", "orange", "grape", "pear", "banana")
list.add("watermelon")
for (fruit in list) {
     println(fruit)
}

mutableListOf()函数用于创建一个可变集合。
同样的,对于Set集合同样存在 setOf()mutableSetOf() 函数,用法类似。
我们再来看一下Map的用法。
按照传统方式我们通常是这样用的:

val map = HashMap<String, Int>()
map.put("apple",1)

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

map["apple"] = 1

而读取数据可以这样写:

val num=map["apple"]

同样的,Kotlin中也对Map提供了mapOf()mutableMapOf() 函数来简化Map的初始化,我们可以直接在Map初始化的时候传入键值对组合:

val map= mapOf("a" to 1, "b" to 2, "c" to 3, "d" to 4)
    for ((letter, num) in map) {
        println("letter is $s,num is $num")
    }

在上述代码的for-in循环中,我们将Map的键值对变量一起声明到了一堆括号中,这样每次进行循环遍历时,便会将遍历结果赋值给这两个键值对变量,然后打印出来。

2. 集合的函数式API

集合的函数式API有很多个,这里我们重点学习函数式API的语法结构(即lambda表达式语法结构)。
需求:找出水果集合中单词最长的水果

val list = listOf("apple", "banana", "orange", "pear", "grape", "watermelon")

//1).传统写法
var maxLenthFruit=""
for (fruit in list) {
     if (fruit.length>maxLenthFruit.length){
         maxLenthFruit=fruit
     }
 }
 
 //2) 函数式Api写法
val maxLenthFruit=list.maxBy {it.length}
println("max length fruit is $maxLenthFruit")

maxBy() 是kotlin集合提供的自带函数,后面跟的{it.length}是Lambda表达式的简化写法。那什么是Lambda呢?简单的说 Lambda就是一小段可以作为参数传递的代码。Lambda表达式的语法结构如下:

	{参数名1:参数类型,参数名2:参数类型 ->函数体}

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

在实际使用中,我们不需要使用Lambda表达式的完整语法结构,而是使用简化写法。下面我们就用“找出水果集合中单词最长的水果”的例子来一步步推导演化,加深理解。

我们首先来了解一下maxBy的工作原理,maxBy接收的是一个Lambda类型的参数,并且会在遍历集合的时将每次遍历的值作为参数传递给Lambda表达式,其工作原理是根据传入的条件来遍历集合,从而找到该条件下的最大值。那么套用Lambda表达式的语法结构我们就可以写出如下代码:

val list = listOf("apple", "banana", "orange", "pear", "grape", "watermelon")
val lambda={fruit:String -> fruit.length}
val maxLenthFruit=list.maxBy (lambda)

变量直接替换:

val maxLenthFruit=list.maxBy ({fruit:String -> fruit.length})

Kotlin规定:当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面

val maxLenthFruit=list.maxBy(){fruit:String -> fruit.length}

接下来,如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略

val maxLenthFruit=list.maxBy {fruit:String -> fruit.length}

然后,由于kotlin拥有出色的类型推导机制,Lambda表达式中的参数在大多数情况下不必声明参数类型,所以进一步简化:

val maxLenthFruit=list.maxBy {fruit -> fruit.length}

最后,当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以直接使用 it关键字 代替

val maxLenthFruit=list.maxBy {it.length}

下面我们再来学习几个集合中比较常用的函数式API。

  • map函数

集合中的map函数是最常用的一种函数式API,它用于将集合中的每个元素都映射成另外一个值,映射的规则在Lambda表达式中指定,最终生成一个新的集合。例如,我们希望所有的水果名称都变成大写:

val list = listOf("apple", "banana", "orange", "pear", "grape", "watermelon")
val newList =list.map { it.toUpperCase() }
for (fruit in newList) {
    print(fruit)
}
  • filter函数
    filter函数是用来过滤集合中的数据的,它可以单独使用,也可以配合前面的map函数使用
val list = listOf("apple", "banana", "orange", "pear", "grape", "watermelon")
val newList = list.filter { it.length<=5 }.map { it.toUpperCase() }
for (fruit in newList) {
     println(fruit)
 }
  • any和all函数
    any函数用于判断集合中是否至少存在一个元素满足指定条件,all函数用于判断结合中是否所有元素都满足条件。
val list = listOf("apple", "banana", "orange", "pear", "grape", "watermelon")
val anyResult = list.any { it.length <= 5 }
val allResult = list.all { it.length <= 5 }
println("anyResult is $anyResult,allResult is $allResult,")

3. Java函数式API的使用

在kotlin中调用java方法时也可以使用函数式API,但有一定的条件限制。如果在kotlin中调用了一个java方法,并且该方法接收一个java单抽象方法接口参数,就可以使用函数式API。单抽象方法接口指的是接口中只有一个待实现方法,如果接口中有多个待实现方法,则无法使用函数式API。比如java中的Runnable接口就是一个单抽象方法。

new Thread(new Runnable(){
	@Override
	public void run(){	
		System.out.println("Thread is running")
	}
}).start();

这是java中写法,如果把上述代码翻译成kotlin版本,写法如下:

Thread(object :Runnable{
   override fun run() {
   		println("Thread is running")
    }
}).start()

Kotlin中匿名类的写法和java有一点区别,由于kotlin完全舍弃了new关键字,因此创建匿名类实例就不能使用new了,而是改用object关键字。上述代码符合java函数式API的使用条件,所以可以简化为:

Thread(Runnable{
	println("Thread is running")
}).start()

因为Runnable类中只有一个待实现方法,即使这里没有显式地重写run()方法,kotlin也能自动明白Runnable后面的Lambda表达式就是要在run()方法中实现的内容。
另外,如果一个java方法的参数列表中不存在一个以上java单抽象方法接口参数,我们还可以将接口名进行省略,进一步精简代码:

Thread({
	println("Thread is running")
}).start()

你以为这就结束了?和之前kotlin中函数式API用法类似,当Lambda表达式是方法的最后一个参数时,可以将Lambda表达式移到方法括号的外面,同时,如果Lambda表达式是方法的唯一一个参数,还可以将方法的括号省略,最终简化结果如下:

Thread{
	println("Thread is running")
}.start()

你可能感兴趣的:(Kotlin学习,lambda,kotlin,android,编程语言)