當Android遇上Kotlin — Day4

Lambda

  • 將函數當作值的功能傳入
// 語法結構
input -> body
input(parameters):
不輸入:()
單個輸入:x
多個輸入:(int x, int y)或簡寫(x,y)
body:
什麼都不做:{}
單行不回傳值:print("NO")
多行不回傳值:
{
print("NO");
print("NO2");
}
單行回傳值:x+y
多行回傳值:
{
x++;
y-=x;
return x+y;
}
  • 使用Runnable來解釋Lambda
// Android
Runnable runnbale = new Runnable() {
public void run() {
System.out.println("run me!");
}
};
// Lambda
Runnable runnbale = () -> System.out.println("run me!");
  • 使用Lambda時,不會多new一個實體出來,而是將Lambda的body區塊先放到記憶體中,透過Call Function的方式來進行呼叫,如此一來可以提升程式效能
// Java
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
/* actions on click */
}
});
// Lambda
button.setOnClickListener { view -> /* actions on click */ }
新觀念:以前必須自己實作所有東西的習慣,現在可以透過Lambda和相關的操作子來改正這習慣
//找出最大年齡
fun findTheOldest(people: List<Person>) {
var maxAge = 0
var theOldest: Person? = null
for (person in people) {
if (person.age > maxAge) {
maxAge = person.age
theOldest = person
}
}
print(theOldest)
}
val people = listOf(Person("Alice", 29), Person("Bob", 31))
findTheOldest(people)
輸出:[Person(name=Bob, age=31)]
// 透過Kotlin
val people = listOf(Person("Alice", 29), Person("Bob", 31))
print(
people.maxBy { it.age })
輸出:[Person(name=Bob, age=31)]
  • 如何簡化Lambda
people.maxBy { it.age }
// 其實最原始的模樣是
people.maxBy({ p: Person -> p.age }) //將person傳入,並回傳age
// 如果他是函數中唯一的參數時,可以將他放置在圓括號外面
people.maxBy() { p: Person -> p.age }
// 並可以將圓括號刪除
people.maxBy { p: Person -> p.age }
// 去除參數類型
people.maxBy { p -> p.age }
// 最後使用it來代替這參數
people.maxBy { it.age }

強大的函數操作子

  • 篩選元素操作子(filter)
val people = listOf(Person("Alice", 29), Person("Bob", 31))
people.filter { it.age > 30 }
輸出:[Person("Bob", 31)]
  • 修改元素操作子(map)
val people = listOf(Person("Alice", 29), Person("Bob", 31))
people.map { it.name }
輸出:[Alice, Bob]
  • 查找元素操作子(find or firstOrNull)
val people = listOf(Person("Alice", 27), Person("Bob", 31))
people.find { it.age <= 27 }
people.firstOrNull { it.age <= 27 }
輸出:[Person(name=Alice, age=27)]
  • 組合元素操作子(groupBy)
val list = listOf("a", "ab", "b")
list.groupBy { String::first} // first 為String的擴展函數,取得第一個字元
輸出:{a=[a, ab], b=[b]}
  • 扁平化集合元素操作子(flatMap)或(flatten)
val strings = listOf("abc", "def")
strings.flatMap { it.toList() }
輸出:[a, b, c, d, e, f]
如果只是單純要扁平化所有集合元素,可直接使用flatten來取代
val strings = listOf("abc", "def").flatten()
  • 將Lambda轉變為函數式接口
  • 假設有一個需要返回函數式接口的方法,你無法直接返回一個Lambda,因為對於Lambda來說他只是一個程式區塊,而不是一個物件,所以你無法直接返回一個Lambda給此函數,必須將他包裝成SAM構造函數
// Java
Runnable runnable = new Runnable() {
@override
public void run() {
...
}
};
// Kotlin 
fun createRunnable(): Runnable {
return Runnable { ... }
}
  • 實作一個可以重用的Lambda函數式接口
val listener = OnClickListener { view ->
val text = when(view.id) {
R.id.button1 -> "First button Clicked"
R.id.button2 -> "Second button Clicked"
else -> "Unknown"
}
    toast(text)
}
button1.setOnClickListener(listener)
button2.setOnClickListener(listener)

With函數

fun alphabet(): String {
val result = StringBuilder()
for (letter in 'A'..'Z') {
result.append(letter)
}
result.append("\nNow I know the alphabet!")
return result.toString()
}
// 使用with函數重構
fun alphabet(): String {
val stringBuilder = StringBuilder()
return with(stringBuilder) {
for(letter in 'A'..'Z') {
this.append(letter)
}
append("\nNow I know the alphabet!")
this.toString()
}
}
One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.