流程控制應該是每種程式語言或多或少都會實作的部份,這也是寫 Code 時必須要了解的核心觀念, Kotlin 流程控制大致
If-Else 是很基礎的條件表達方法,Kotlin 中的基本使用規則與 Java 相同
Example:
val a: Int = 1
val b: Int = 10
if (a > b) {
print("$a is bigger")
} else {
print("$b is bigger")
}
提供另一種 Kotlin 中常見的寫法,可把判斷或執行直接交給變數處理
val a: Int = 1
val b: Int = 10
val max: Int = if (a>b) a else b
print(max) // Output: 10
另外,值得一提的是 Kotlin 沒有三元運算子(Ternary operator)的表達方法,即 condition ? then : else
,根據開發團隊說法, 他們認為 If 已經夠用了,所以就不克提供。雖然 Kotlin 沒有支援三元運算子但有提供貓王運算子( Elvis oprator),這之後在 Null Safety 會再探討,有興趣的可以參考我之前寫過的介紹 長的帥,連Code都是香的 - Elvis Operator ?:
Kotlin 中的 When 與 C langage 與 Java 中的 Switch-case 相同,基礎用法如下
Example:
val a: Int = 1
when (a) {
1 -> print("a == 1")
2 -> print("a == 2")
else -> print("a is neither 1 nor 2")
}
// Outout: a == 1
而 Kotlin 的 when 還有幾種變化型
val a: Int = 1
when (a) {
0, 1 -> print("a == 0 or a == 1")
2 -> print("a == 2")
else -> print("a is neither 1 nor 2")
}
// Outout: a == 0 or a == 1
val a: Int = 30
when (a) {
in 1..10 -> print("a is in 1 to 10")
!in 11..20 -> print("a is outside of range")
else -> print("none of the above")
}
// Output: a is outside of range
when(val result = client.requestUserProfile(userId)) {
is UserProfileResult.Success -> print(result.userProfile)
is UserProfileResult.Error -> print("Get some error: ${result.Error}")
}
val a = 10
when {
a % 2 != 0 -> print("$a is odd")
a % 2 == 0 -> print("$a is even")
}
// Output: 10 is even
因為 when 的寫法與變化有很多種,因此 when 在 Kotlin 中的應用場景也是非常多,尤其是在處理 Error handler 的時候,更是會頻繁的出現 when 判斷喔
相信有寫程式的開發者一定對 Loops 不陌生,基本上用法和其他程式語言都非常相似
For-loops 提供 Iterator 遍歷所有內容,在 For-loop 中,會隱式方法獲取 Iterator
Example:
val numbers = listOf("one", "two", "three")
for (item in numbers) {
println(item)
}
// Output:
// one
// two
// three
For-loop 可以搭配 range expression 達到更多元的操作
Example:
for (i in 1..3) {
println(i)
}
// Output:
// 1
// 2
// 3
for (i in 10 downTo 0 step 2) {
println(i)
}
// Output:
// 10
// 8
// 6
// 4
// 2
// 0
另外補充一篇滿有趣的文章,是我在查 Iterator 時發現的
他提供了一個很有趣的問題,讓我們先來看看問題長怎樣:
// 當 list 元素內容是 [1, 3, 5] 時,執行會是正確的
val list = mutableListOf(1, 3, 5)
for (i in list) {
if (i.equals(3)) list.remove(i)
}
println(list)
// Output: [1, 5]
// 然而,當 list 元素內容是 [1, 2, 3, 4, 5] 時,會報錯誤訊息
val list = mutableListOf(1, 2, 3, 4, 5)
for (i in list) {
if (i.equals(3)) list.remove(i)
}
println(list)
// Output:
// Exception in thread "main" java.util.ConcurrentModificationException
// at java.util.ArrayList$Itr.checkForComodification (ArrayList.java:909)
// at java.util.ArrayList$Itr.next (ArrayList.java:859)
// at FileKt.main (File.kt:3)
看完上面的例子,是不是滿頭問號,難道是7月鬼門開,乖乖放不夠多所以 Compiler 不乖乖嗎?
這篇文章有深入去探討 Iterator的源碼,並且透過源碼也應證實作 Iterator 時,不要用集合自帶的方法去改變集合結構(例如 remove),而應該用 Itereator 自帶的方法對集合做操作,在 Kotlin 中可以用 filter
達到,這個例子我用到了 Higher-order function 和 Scope function,這些之後都會寫文章探討喔
val list = mutableListOf(1, 2, 3, 4, 5)
list.filter {
!it.equals(3)
}.apply {
println(this)
}
而我也是在用 Kotlin 實作這篇文章時,才發現原來 Kotlin Iterator 底層實作是 Java 的 Iterator,因此錯誤訊息等等都指向 Java exception,又學了一課
while 和 do..while 用法本質上和 C 或 Java 用法一致,這篇就不多花時間探討
var a = 3
while (a > 0) {
println(a)
a--
}
// Output:
// 3
// 2
// 1
在 Java 中 Return 使用非常常見,這種編寫方式在 Kotlin 中也有被保留下來
fun main() {
println(sum(1, 10))
}
fun sum(a: Int, b: Int): Int {
return (a + b)
}
但如果 return 是表達式,就可以省略 return
fun main() {
println(sum(1, 10))
}
fun sum(a: Int, b: Int) = a + b
continue 與 break 都是用來控制循環結構式,能達到中斷或跳過,目的與 Java 中的相同
Example:
for (i in 1..10) {
if (i % 2 == 0) continue
println(i)
}
// Output:
// 1
// 3
// 5
// 7
// 9
Example:
for (i in 1..10) {
if (i % 2 == 0) break
println(i)
}
// Output:
// 1
但如果在 forEach 方法裡面用 continue 與 break ,Compiler 會回傳 'break' and 'continue' are only allowed inside a loop
錯誤
因此我們要在 forEach 裡使用 Label 達到 continue 與 break 的效果,而且上面提到跳轉語句的用法,在 Kotlin 中也可以搭配 Label 做使用, Label 的用法就像奇異博士的傳送門,只需要加上標示符 @ 符號,就可以在表達式之間穿梭
Example:
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit
print(it)
}
print(" done with explicit label")
// Output: 1245 done with explicit label
// 另外一種用法
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach
print(it)
}
print(" done with explicit label")
// Output: 1245 done with explicit label
今天介紹了 Kotlin 中該如何做到條件控制,以及探討了一個 Iterator 的問題。
明天會開始介紹 NullSafety ,以及如何將 NullSafety 結合 Scope function 和 Extension function。