4.1 條件控制
4.1.1 if
if
敍述 (if-statement) 就是條件選擇,當條件符合時才執行區塊中的程式,還可以加上 else
來表示當條件不符合時要執行的區塊。
傳統的 if
敍述語法和大多數程式語言一樣,請看範例:
// 情境一
var max = a
if (b > a) {
max = b
}
// 情境二
var max: Int
if (a > b) {
max = a
} else {
max = b
}
在這種情況下使用 if
敍述其實很沒效率,Kotlin 提供 if
表達式 (if-expressions) 語法,可以讓我們一行就完成上面的例子:
val max = if (a > b) a else b
敍述 (statement) 和表達式 (expression) 的差異在於,敍述是一個獨立的程式碼區塊,而表達式可以被當成值指派給變數或從函式中回傳,也就是說,表達式可以放在指派符號 =
的右邊,而敍述不行。
在可以使用 if
表達式的情境使用它,可以使程式碼變得簡潔及嚴謹。以此例來說,原本使用 var
宣告現在改成 val
,這樣可以大大減少後續程式碼不小心改到變數的值的機會,而且符合優先使用 val
的準則;再來,程式碼只有一行,寫的少犯錯的機會就減少,閱讀上可以明確得知這段條件判斷的目的,較不容易造成誤解或想半天才知道在做什麼。
讀者可能有發現,if
表達式的語法很像 Java 中的三元運算子 (a > b) ? a : b
,但是 Kotlin 沒有三元運算子,我們不需要額外多記一種語法,使用 if
表達式即可。if
表達式不只可以用在變數中,還可以用在函式,看看以下例子:
// 一般函式的寫法
fun max(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}
// 現在我們知道怎麼用 if 表達式了,可以改寫成
fun max(a: Int, b: Int): Int {
return if (a > b) a else b
}
// 如果搭配函式表達式的話
fun max(a: Int, b: Int) = if (a > b) a else b
程式碼可以由 7 行縮短為 1 行,不僅寫起來、讀起來更快,程式碼的意圖也更加清楚。
如果 if
表達式內的程式碼不只一行,可以用大括號 {}
包起來,但是必須把結果值放在最後一行,而且不可以加 return
,請看範例:
val max = if (a > b) {
println("a 比較大")
a // 結果值放在最後一行,不要加 return
} else {
println("b 比較大")
b // 結果值放在最後一行,不要加 return
}
另外,使用 if
表達式的時候,一定要有 else
區塊,因為無論如何一定要有值,才能指派給變數。
4.1.2 when
Kotlin 沒有 switch
這個關鍵字,而是設計了 when
敍述來取代它,請看範例:
val x: Any = 1
when (x) {
1 -> print("x 是 1")
2,3,4 -> print("x 可能是 2 或 3 或 4")
in 5..10 -> print("x 在 5~10 的範圍內")
is Int -> print("x 是整數")
else -> {
print("無法判斷 x")
}
}
when
敍述可以使用括號 ()
來接受要比對的參數,每個比對條件寫成一行,條件寫在前面,後接箭號 ->
表示符合時要如何處理。條件比對的靈活度很高,可以是單一值、多個值 (使用逗號分隔)、一段範圍 (使用 in
關鍵字) 等等,如果都不符合,會執行 else
條件的內容。遇到處理程式較多行時,可以用大括號 {}
包圍,如同範例中的 else
區塊。
我們不一定要使用括號 ()
來接受參數,可以直接寫在比對條件中,前例可以改寫如下:
val x: Any = 1
when {
x == 1 -> print("x 是 1")
x == 2 || x == 3 || x == 4 -> print("x 可能是 2 或 3 或 4")
x in 5..10 -> print("x 在 5~10 的範圍內")
x is Int -> print("x 是整數")
else -> {
print("無法判斷 x")
}
}
這裡只是舉例,建議使用前一種寫法較佳。
有時候當 if-else
條件過多時,建議改用 when
較佳,例如:
// 避免這種寫法
if (a == 0) {
// ...
} else if (a < 100) {
// ...
} else if (a in 100..200) {
// ...
} else {
// ...
}
// 改用 when 來增加易讀性
when {
a == 0 -> // ...
a < 100 -> // ...
a in 100..200 -> // ...
else -> // ...
}
如果所有可能條件都列出時,可以省略 else
。
when
一樣可以當成表達式,放在 =
的右邊,請看範例:
val x: Any = 100
val msg = when (x) {
1 -> "x 是 1"
2,3,4 -> "x 可能是 2 或 3 或 4"
in 5..10 -> "x 在 5~10 的範圍內"
is Int -> "x 是整數"
else -> {
// 這裡可以寫很多東西,但是記得要把結果值放在最後一行
println("...")
"無法判斷 x"
}
}
println(msg) // x 是整數
記住,表達式最後一定會有一個結果值。如果使用大括號 {}
,記得要把結果值放在最後一行,而且不要加 return
。
寫過 Java 的讀者可能有發現,以上的例子竟然沒有 break
關鍵字,沒錯!when
的條件判斷並不會像 Java 的 switch
敍述一樣自動向下執行,所以不必使用 break
來終止。
註:Java 13 將有新版本的 switch 表達式 預覽版,用起來很像 when
。
4.2 條件控制
4.2.1 for
Kotlin 的 for
迴圈以範圍來決定循環次數,或以疊代的方式遍歷陣列或集合中的每個項目。Kotlin 沒有 Java 這種從 C 語言一直延續到現在的傳統 for
迴圈,請看範例:
/* Java */
for (int i = 0; i < 10; i++) {
System.out.print(i);
}
這種迴圈讀起來不直覺,寫起來也麻煩。在 Kotlin 中可以使用 for in
迴圈,以雙點 ..
來指定範圍,看看以下的例子:
for (i in 0..9) {
print(i)
}
// 或
for (i in 0.rangeTo(9)) {
print(i)
}
// 或
for (i in 0 until 10) { // <== 不包含 10
print(i)
}
// [結果] 0123456789
Kotlin 的 for in
迴圈和傳統 for
迴圈的行為是一樣的,但是語意較清楚、也較易閱讀。其中 in
關鍵字會將變數 i
的值限制在指定範圍內,並在每次循環時取得一個累進 1
的值。
設定範圍的方式有兩種,如果要將頭尾值都包含在內用 ..
,如果不包含尾端的值,像是前面 Java 的例子 i < 10
一樣,就用 until
;簡單地說就是 ..
(兩個點) 是「從頭到尾」,until
則是「神龍見首不見尾」。
如果循環順序要反過來,也就是從大到小,可以使用 downTo
:
for (i in 9 downTo 0) {
print(i)
}
// 或
for (i in 9.downTo(0)) {
print(i)
}
// [結果] 9876543210
預設每次循環是累進 1
,即跳 1
階,如果要一次跳 N
階,可以使用 step
來指定:
for (i in 0..9 step 3) {
print(i)
}
// 或
for (i in 0.rangeTo(9).step(3)) {
print(i)
}
// [結果] 0369
我們也可以使用 for in
迴圈來疊代陣列或集合,請看範例:
val names = listOf("Tony", "Tom", "Tiffany")
for (name in names) {
println(name)
}
/* --- 結果 ---
Tony
Tom
Tiffany
*/
傳統 for
迴圈對陣列或集合循環時,可以依索引值來取得項目。在使用 for in
迴圈時如果需要索引值,可以使用 withIndex()
方法,請看範例:
val names = listOf("Tony", "Tom", "Tiffany")
for ((index, name) in names.withIndex()) {
println("$index: $name")
}
/* --- 結果 ---
0: Tony
1: Tom
2: Tiffany
*/
Kotlin 還有一個方便的屬性叫做 indices
,它會回傳陣列或集合的範圍,這樣我們就可以省去自己指定範圍的動作,前面的例子可以改寫如下:
for (index in names.indices) {
println("$index: ${names[index]}")
}
以此例來說,indices
會回傳一段範圍值 0..2
。善用 indices
可以避免存取索引值時超過陣列或集合範圍的例外。
4.2.2 while
以條件來決定循環次數的迴圈有兩種型式,一種是先判斷條件是否符合才執行的 while
迴圈,另一種 do while
則是先執行才判斷條件是否符合。先來看看 while
迴圈:
var i = 5
while (i > 0) {
println(i)
i--
}
// 54321
當條件成立,while
迴圈就會執行區塊中的程式。使用 while
迴圈要小心在沒有離開條件或離開條件無法達成的情況下,會形成無窮迴圈,以上例而言,只要把 i--
拿掉,就形成無窮迴圈,因為 i
將永遠大於 0
,條件永遠成立。
另一種 do while
迴圈會先執行區塊中的程式才去檢查條件:
var i = 1
do {
println(i)
i--
} while (i > 0)
// 1
這種迴圈的特性是,無論如何都至少會執行一次區塊中的程式。
4.2.3 離開迴圈
在實務上,我們可能會使用迴圈在集合中尋找資料,一旦找到符合的資料,就沒必要再繼續執行迴圈,這時候就需要有中途離開迴圈的方法。
有 3 個關鍵字可以離開迴圈:
- 返回
return
:跳離迴圈所在的函式,可以同時回傳值。 - 中斷
break
:離開目前的迴圈。 - 繼續下一回
continue
:中止目前這一輪迴圈的執行,直接跳到迴圈的開頭,執行下一輪。
return
return
會跳離迴圈最接近的函式。不管是否為巢狀迴圈 (即迴圈中還有另一個迴圈),永遠會跳離最接近的函式,請看範例:
fun demo() {
for (i in 0..1) {
println("for(i) 開始: $i")
for (j in 0..3) {
println("for(j) 開始: $j")
if (j == 2) {
println(">>> 離開 demo()")
return
}
println("for(j) 結束: $j")
}
println("for(i) 結束: $i")
}
println("函式結束")
}
/* --- 結果 ---
for(i) 開始: 0
for(j) 開始: 0
for(j) 結束: 0
for(j) 開始: 1
for(j) 結束: 1
for(j) 開始: 2
>>> 離開 demo()
*/
我們可以看到,當 return
一被執行,就直接離開 demo()
函式了。
接下來,看看巢狀函式的例子:
fun outer() {
println("outer() 開始")
fun inner() {
println("inner() 開始”)
for (i in 0..3) {
println("for(i) 開始: $i")
if (i == 2) {
println(">>> 離開 inner()")
return
}
println("for(i) 結束: $i")
}
println("inner() 結束")
}
inner()
println("outer() 結束")
}
/* --- 結果 ---
outer() 開始
inner() 開始
for(i) 開始: 0
for(i) 結束: 0
for(i) 開始: 1
for(i) 結束: 1
for(i) 開始: 2
>>> 離開 inner()
outer() 結束
*/
我們可以看到,return
離開了 inner()
後還繼續執行 outer()
中的程式。
break
中斷並離開目前的迴圈,請看範例:
for (i in 0..2) {
for (j in 0..2) {
println("($i, $j)")
if (j == 0) {
break
}
}
}/* --- 結果 ---
(0, 0)
(1, 0)
(2, 0)
*/
break
只會中斷並離開靠近它的那個迴圈,以巢狀迴圈來舉例就能看得出來。但是某些情況下,我們想要離開外面那個迴圈,該怎麼做呢?Kotlin 針對迴圈提供了標籤,標籤以 標籤名稱@
來表示,我們就可以使用 break@標籤名稱
來指定要跳離的迴圈,請看範例:
loop@ for (i in 0..2) {
for (j in 0..2) {
println("($i, $j)")
if (j == 0) {
break@loop
}
}
}
/* --- 結果 ---
(0, 0)
*/
和前例相同,只是這次我們直接跳離外部迴圈。
continue
和 break
類似,只不過它不會離開迴圈,而是直接進行下一回的循環,請看範例:
for (i in 0..2) {
if (i == 1) {
continue
}
println(i)
}
/* --- 結果 ---
0
2
*/
1
被跳過了。continue
一樣可以搭配標籤來使用,指定跳到某個標籤的迴圈進行下一回的循環。
repeat
如果只是單純想要重覆執行某段程式碼一定的次數,可以使用 repeat,請看範例:
fun main() {
repeat(3) {
println("Hello")
}
}
/*
Hello
Hello
Hello
*/
繼續閱讀:Kotlin 實戰範例 (5) 基礎 (函式、套件)
完整內容可以參考電子書:Google Play Pubu 樂天 Kobo
由 Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀
我要留言
留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。