3.1 集合创建与遍历
3.1.1 List和Set集合
传统意义上,集合主要是List和Set,再广泛一点,还有Map这样的键值对数据结构。这些在Java中都是接口,List主要实现类是ArrayList和LinkedList,Set的主要实现类是HashSet,Map的主要实现类是HashMap。
现在需要创建一个包含许多水果名称的集合,在Java中:
var list = ArrayList<String>()
list.add("apple")
list.add("banana")
list.add("pear")
在Kotlin也可以这样做,但还有更简单的方法:
var list = listOf("apple","banana","pear")
需要注意的是,listOf()方法创建的是不可变的集合(元组),不可对集合进行添加、删除或修改操作
要创建可变的集合,需要使用mutablelistOf()方法
Set集合与List集合使用方法相近,但需注意Set集合底层使用hash映射机制存放数据,故集合元素不能保证有序
val list= mutableListOf("apple","banana","pear")//创建可变集合list
list.add("watermelon")
//set集合创建方法与list相近,使用setOf()和mutableSetOf()方法
val set= mutableSetOf("apple","banana","pear")//创建可变集合Set
//需要注意的是,Set集合底层使用hash映射机制存放数据,故集合元素不能保证有序
3.1.2 Map集合
Map是一种键值对形式的数据结构,传统Map用法是创建一个HashMap实例,再分别将键值对数据添加到Map中
val map=HashMap<String,Int>()//创建HashMap实例
map.put("apple",1)//用put方法添加键值对数据
map.put("banana",2)
map.put("pear",3)
val a=map.get("apple")//用get方法获取值
Kotlin中还有更简单的操作,这是一种类似数组下标的语法结构
val map=HashMap<String,Int>()//创建HashMap实例
map["apple"]=1//添加键值对数据
map["banana"]=2
val a=map["apple"]//获取值
Kotlin还提供了mapOf()和mutableMapOf()方法进一步简化了Map的用法
val map= mutableMapOf("apple" to 1,"banana" to 2,"pear" to 3)
for((fruit,num) in map) {//遍历键值对集合
println("fruit is " + fruit + ", number is " + num)
}
3.2 集合的函数式API
3.2.1 maxBy()
对于需求:取得集合中名字最长的水果,我们有方法:
val list = listOf("apple","banana","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","pear")
val maxLengthFruit=list.maxBy { it.length }
println("max length fruit is "+maxLengthFruit)
正常情况下,我们只能向函数传入变量,但借助Lambda可以传入一小段代码(长度无限制,但不建议将过长的代码写入Lambda表达式,影响代码可读性)
Lambda表达式的语法结构为:{参数名1:参数类型,参数名2:参数类型 -> 函数体}
大部分情况下,我们只需要使用其结构的简化版本
接上例,maxBy()方法接受了一个Lambda类型的参数,并在遍历集合时将每次遍历的值作为参数传递给Lambda表达式
maxBy()的工作原理是根据传入的条件遍历集合,来找到该条件下的最大值
对上例的Lambda表达式展开:
val list = listOf("apple","banana","pear")
//Lmabda表达式的完整形式
val lambda = {fruit:String->fruit.length}
val maxLengthFruit=list.maxBy(lambda)
我们再对展开的Lambda表达式进行简化:
val maxLengthFruit = list.maxBy({fruit:String -> fruit.length})//Lambda表达式可以作为参数直接传入函数
val maxLengthFruit = list.maxBy(){fruit:String -> fruit.length}//若Lambda参数是函数的最后一个参数时,可以将其放在括号外
val maxLengthFruit = list.maxBy{fruit:String -> fruit.length}//若Lambda参数是函数的唯一参数时,括号可省略
val maxLengthFruit = list.maxBy{fruit -> fruit.length}//Lambda表达式的参数列表在大多数情况下不需要声明参数类型
val maxLengthFruit = list.maxBy{it.length}//Lambda表达式的参数列表只有一个参数时,不必声明参数名,可用it关键字代替
3.2.2 map()
map()方法可以将集合内每个元素都映射成另外的值,映射规则在Lambda表达式中指定,并产生一个新的集合,
如对上例集合元素全部转为大写字母:
val list = listOf("apple","banana","pear")
val newList = list.map{it.toUpperCase()/*转为大写*/}//映射后得到新集合
3.2.3 filter()
filter()方法用于过滤集合中的数据,
如对上例建立新映射,只保留5个字母以内的水果:
val list = listOf("apple","banana","pear")
val newList = list.filter { it.length <= 5 /*过滤集合数据,只保留长度<=5的数据*/}.map{it.toUpperCase()/*转为大写*/}
注意,本例对集合先调用filter()方法,再调用map()方法,这样减少了映射转换的元素数量,提高了效率
3.2.4 any(),all()
any()方法用于判断集合中是否至少存在一个元素满足指定条件
all()方法用于判断集合中是否所有元素都满足指定条件
val list = listOf("apple","banana","pear")
val anyRes = list.any { it.length <= 5 }
val allRes = list.all { it.length <= 5 }
println("anyRes is "+anyRes)
println("allRes is "+allRes)
结果如下:
anyRes is true
allRes is false
3.3 Java函数式API的使用
JavaAPI中的Runnable接口,只要能实现该接口的Java方法,就可以使用函数式API
如Java的线程类Thread:
new Thread(new Runnable(){//使用匿名类提供实例化对象
@override
public void run(){
System.out.println("Thread is running");
}//我们创建了Runnable接口的匿名类实例,并将其传给Thread类的构造方法,
}).start();//最后调用Thread类的start()方法执行这个线程
如果用Kotlin实现这段代码:
Thread(object: Runnable{//Kotlin中舍弃了new关键字,因此创建匿名类时用到object
override fun run(){
println("Thread is running")
}
}).start()
如果使用Java函数式API:
Thread(Runnable{//因为Runnable类只有一个方法需要实现,因此即使不显式重写run()方法,Kotlin也明白Runnable后面的Lambda表达式
println("Thread is running")//是在run()方法中的内容
}).start()
当我们在使用Android SDK时,用到的许多函数也是Java语言编写,因此会经常用到Java函数式API
例如Android中常用的点击事件接口OnClickListener:
public interface OnClickListener{
void onClick(View v);//可以看到,该接口只有一个方法需要实现
}
假设我们现在拥有一个按钮button实例,用Kotlin代码注册该按钮的点击事件:
button.setOnClickListener{
}
注意,Java函数式API的使用都限定于从Kotlin中调用Java方法,而且单抽象方法接口也必须是用Java语言设计的