文章目錄
- 函數式程式設計
-
- 舉個栗子:forEach
- 傳統寫法的缺點
- 高階函數
-
- maxBy、minBy
- filter
- map
- any
- count
- find
- groupBy
- 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程式員,這個需求對于他們來說就太簡單了
maxBy方法傳回第一個滿足指定評判标準的最大值
也可以找到年齡最低的舍友
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)
}
}
調用的時候就可以直接空格調用了
運作結果是一樣的