iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 4
0
Software Development

Kotlin 島深度之旅 30 天系列 第 4

[Day 4] Kotlin Journey - 變數 (Variables) & 控制流程

今天繼續探討 變數和 null-safety

?. 和 !!.

這裡宣告了 name 是可 null 的變數, 如果要對此變數做操作 Kotlin 是不允許的

https://ithelp.ithome.com.tw/upload/images/20200913/20129902sKOdYKims2.png

從錯誤提示可以看到可以使用 ?. 或 !!. 來完成操作

?. 會判斷變數是否為 null, 若是 null 就不會執行 toUpperCase() 了

!!. 則會繼續執行, 可以看到結果會拋出 Exception

fun main() {
    var name: String? = null
    println(name?.toUpperCase()) // null
    println(name!!.toUpperCase()) // throw kotlin.KotlinNullPointerException
}

結果:
null
Exception in thread "main" kotlin.KotlinNullPointerException
	at day4.AppKt.main(App.kt:10)
	at day4.AppKt.main(App.kt)

所以通常都是使用 ?. , !!. 只有用在很確定這個值不是 null 的時候

Elvis operator (貓王運算子 ?:

會這樣取名是因為 ?: 就像貓王的髮型一樣, 很有趣吧 XD

這個運算子可以直接幫我檢查是否為 null, 並給一個預設值

// Elvis operator
val name2: String = name ?: "default name" // default name
println(name2)

是不是很方便? 在 Java 裡面就可能還要用三元運算式(Ternary operator)寫成這樣...寫久了其時蠻囉唆的

String name2 = (name != null) ? name : "default name";

順帶一題, Kotlin 沒有三元運算式

https://ithelp.ithome.com.tw/upload/images/20200913/201299028Qn2fUwWUh.png

真的要類似這樣的方式, 就用 if else 吧

變數類型

在 Java 的時候, 有所謂的 8 大基礎類型和最常用的 String

Java 8 大基礎類型

  • int
  • double
  • float
  • short
  • long
  • byte
  • char
  • boolean

和相對應的 Wrapper Class

而在 Kotlin 內比較簡潔, 就是直接以下的 9 種基礎類型, 沒有在分 class 了

  • String
  • Int
  • Double
  • Float
  • Short
  • Long
  • Byte
  • Char
  • Boolean

equlity

	val name4 = "tim"
    val name5 = "TIM"
    println(name4.toUpperCase() == name5) // true, 內容相等
    println(name4.toUpperCase() === name5) // false, 物件指向的記憶體位置不同

由此可以看到, 有別於以往 Java 還需要用 .equals() 去比較字串內容, Kotlin 其實採用了最直覺的比較方式, 因為一般來說常比較的其實都是變數內的, 而不是物件的記憶體位置

以下是 Kotlin 與其他語言 equlity 比較的圖表

判斷物件的值或記憶體相等的用法

Column 1 Kotlin Java
物件內的值(value) == .equals()
物件的記憶體位置(memory address) === ==

順帶一提, 因為在 Java 中內容一樣的字串創立會共用 string pool, 在 Kotlin 裡面也一樣, 所以以下的例子, 無論內容和記憶體位置都是相同的!

	val name6 = "tim"
    val name7 = "tim"
    println(name6 == name7) // true, 內容相等
    println(name6 === name7) // true, 物件指向的記憶體位置相同, 在 java 中, 內容一樣的字串創立會共用 string pool

if else

if else 在 Kotlin 中, 其實跟其他語言差不多, 讓我們看一下範例

	val address: String? = null
    if (address != null) {
        println("address is $address") // address is null
    } else {
        println("address is null")
    }

但官方的範例有著更簡潔的寫法, 如此可以一句判斷後把結果賦予到 max 變數上

(這跟 Goolgle Java code style 不大一樣, 但在 Kotlin 的 Goolgle 官方 style 確是可以這樣來寫的, 可以參考這裡 https://developer.android.com/kotlin/style-guide#expressions)

	// as expression
    val num1 = 10
    val num2 = 12
    val max = if (num1 > num2) num1 else num2

也可以寫成這樣, 這樣的寫法只要在 block 內最後一個的變數不用寫 return 就可以變成回傳值!

	val max2 = if (num1 > num2) {
        print("max is num1")
        num1
    } else {
        print("max is num2")
        num2
    }

when

Kotlin 的 when 相當好用也很清楚明瞭, 這裡我建立了一個 fun, 參數型態設為 Any, 這樣任何型態都可以傳入, 方便測試

這裡使用了幾個狀況

  • in 1..99 是 range (數值範圍)的使用方式
  • in 集合(list, set..等等)
  • !in 來表示不存在集合裡面
  • is 比對型態 (像是 Java 的 instanceOf)
  • !is
  • else: 一定要寫, 對應不到時預設值

這個例子來說, 整個 when 的判斷後的結果會以 → 對應到結果的字串, 最後再賦予給 result 變數

fun whenFun(num: Any) {
    val result = when (num) {
        0 -> "it's zero"
        in 1..99 -> "it's between 1 to 99" // 使用 range 來比對(1~99)
        100, 101 -> "it's 100 or 101" // 100 或 101
        in listOf("a", "b", "c") -> "in some list" // 確認 num 是否在這 list 裡面
        !in setOf("a", "b", "c") -> "not in this set" // 確認 num 是否 不在這 set 裡面
        is Int -> "it's Integer" // 型態是否是 Int
        is String -> "it's String" // 型態是否是 String
        is BigDecimal -> "it's BigDecimal" // 型態是否是 BigDecimal
        !is Double -> "it's not Double" // 型態不是 Double
        else -> "not match" // 對應不到時預設值
    }
    println(result)
}

呼叫後可以得到以下結果

fun main() {
	whenFun(98) // it's between 1 to 99
    whenFun("c") // in some list
    whenFun(1000) // it's Integer
    whenFun(BigDecimal.ONE) //it's BigDecimal
}

在上面的 when 的例子也可以發現到, 不用 break 就可以完成耶!

以前寫 Java 的話都要 break; 不然會形成一個災難啊...

switch(a) {
    case 1:
        // ..
        break;
    case 2:
        // ..
        break;
    case 3:
        // ..
        break;
}

for

普通的 for 語法像是這樣

// for example
val numList = listOf(1, 2, 3, 4, 5, 6)
for (num in numList) { // for in
    println(num)
}

forEach

要寫的 lambda 一點的風格可以使用 forEach

只有一個參數時, 在 lambda 裡面可以直接使用 it 此參數

// forEach
numList.forEach { num -> println(num) }
numList.forEach { println(it) } 

while, do while

while 跟其他語言相同, do while 差別在於 do 裡面的程式碼會先執行, 在做 while

// while
val end = 5
var i = 0
while (i < end) {
    println(i)
    i++
}

// do while
var j = 0
do {
    j++
    println("do while $j")
} while (j < end)

repeat

repeat 也是 lambda 的寫法, 語法很簡單, 下面這樣就是重複 0~4

// repeat
repeat(5) { println(it) }

以上就是今天的內容!!我們明天見!

今日練習的程式在這: 請點我


上一篇
[Day 3] Kotlin Journey - 變數 (Variables)
下一篇
[Day 5] Kotlin Journey - 函數 (function)
系列文
Kotlin 島深度之旅 30 天31

尚未有邦友留言

立即登入留言