天天看點

Kotlin 學習筆記 整理

1、在 Kotlin 中類可以有屬性,我們可以使用 :

 1.1、var 關鍵字聲明可變屬性:

var x = 5 // `Int` type is inferred
x += 1
           

 1.2、val 關鍵字聲明隻讀屬性:

val a: Int = 1  // 立刻指派
val b = 2   // `Int` 類型是自推導的
val c: Int  // 沒有初始化器時要指定類型
c = 3       // 推導型指派
           

2、空安全

 2.1、"?" -> 聲明為可空的變量  

var b: String? = "abc"
b = null
           

 2.2、"?." -> 如果 b 不為空則傳回長度,否則傳回空。這個表達式的的類型是 Int?

b?.length()
           

 2.3、"?:" -> 如果 "?:" 左邊表達式不為空則傳回,否則傳回右邊的表達式。(注意:右邊的表帶式隻有在左邊表達式為空是才會執行)

val l = b.length()?: -1
           

 2.4、"!!" -> 傳回一個非空的 b 值 或者如果 b 為空,就會抛出一個 NPE(空指針) 異常:

val l = b!!.length
           

 2.5、"=="與"===" -> "=="判斷值是否相等,"==="判斷值及引用是否完全相等。

val num: Int = 128;
val a:Int? = num
val b:Int? = num
println(a == b)
print(a === b) 
           

3、Kotlin常用操作符  

 3.1、"?:" Elvis操作符

      如果 "?:" 左邊表達式非空,elvis操作符就會傳回左邊的結果,否則傳回右邊的結果。請注意,僅在左側為空的時候,右側的表達式才會計算

val a = b?.length?:-1

//等同于:

val a: Int = if(b != null) b.length else -1
           

 3.2、"as?" 安全轉換 

      當使用 as 轉型的時候,可能會經常出現 ClassCastException。 是以,現在可以使as?安全轉型,當轉型不成功的時候,它會傳回 null。

 注:在使用intent傳值的時候,會出現空字元串不能用as強制轉型,這是應該使用as?

 val m: Int? = a as? Int
           

 3.3、":" 冒号 用于類的繼承,變量的定義 

      1、類型和超類型之間的冒号前要有一個空格 

      2、執行個體和類型之間的冒号前不要空格

 //定義全局變量時
 var str: String? = null

 //類的繼承與變量定義
 class TestActivity<T : Serializable>(str: String) : Activity{} 
           

 3.4、"is" 類型判斷符

      檢查某個執行個體是否是某個類型,如果判斷出屬于某個類型,那麼判斷後的分支中可以直接可當該類型使用,無需顯示轉換

  fun getStringLength(obj: Any): Int? {
        //obj在&&右邊自動動轉換成"String"類型
        if (obj is String && obj.length > 0)
            return obj.length
        return null
  }
           

 3.5、".."、"until" 操作符 以及 "in" 和 "!in" 操作符

      ".." 代表從x到y,包括x和y,這是一個閉區間運算符,而

     "until" 則是半閉區間運算符,代表從a到b範圍内所有的值,包括a和不包括b。 

      "in" 代表在一個區間中,"!in" 代表不在一個區間中。

 if (i in 1..10) { // 等價于 1 <= i && i <= 10
     println(i)
 }
           

 //使用until函數,建立一個不包括其結束元素的區間

 for (i in 1 until 10) {   // i in [1, 10) 排除了 10
      println(i)
 }
           

 3.5.1、downTo()函數

//區間内循環:
for (i in 4 downTo 1){
   print(i) //倒叙周遊
}   
// print “4321”
           

 3.5.2、step()函數 可以進行任意數量的疊代,而不是每次變化都是1

for (i in 1..4 step 2) print(i) // prints "13"
for (i in 4 downTo 1 step 2) print(i) // prints "42"
           

 3.6、多行輸入符 三個雙引号

      三引号的形式用來輸入多行文本,也就是說在三引号之間輸入的内容将被原樣保留,之中的單号和雙引号不用轉義,其中的不可見字元比如/n和/t都會被保留

val str = """ 
           one
           two
           """
//等價于          
val str = "one\ntwo"       
val str =  "one" +"\n"+"two"
           

 3.7、"::"符号 得到類的Class對象

 startActivity(Intent([email protected], MainActivity::class.java))
           

 3.8、"@"符号 

 3.8.1、限定this的類型

      
class User {
      inner class State{
         fun getUser(): User{
             //傳回User
             return [email protected]
         }
         fun getState(): State{
             //傳回State
             return [email protected]
         }
      }
}

           

 3.8.2、作為标簽(見4.6詳解)

 3.9、"$"操作符

      字元串可以包含模闆表達式,及一小段代碼,會求值并把結果包含到字元串中。模闆字元串以美元符号$開頭,由一個簡單的名字構成: 

 val value:Int=5;
 val str:String="the value is $value"
 
 println("itemB:$itemB")
 //字元串模闆
 var userInfo = "name:${user.name},  age:$age"
           

 或花括号括起來的任意表達式

 val g:Int=2
 val h:Int=3
 val str:String="g+h=${g+h}"
           

 轉義字元串和原生字元串都支援模闆字元串。如果想要在原生字元串中使用$(它不支援反斜杠轉義),可以使用以下文法:

 val str:String="""the price is ${'$'}199"""
           

 4、條件表達式的使用

 4.1、"if/else" 語句規則:

      ①if後的括号不能省略,括号裡表達式的值最終必須傳回的是布爾值

      ②如果條件體内隻有一條語句需要執行,那麼if後面的大括号可以省略,但這是一種極為不好的程式設計習慣。

      ③對于給定的if,else語句是可選的,else if 語句也是可選的

      ④else和else if同時出現時,else必須出現在else if 之後

      ⑤如果有多條else if語句同時出現,那麼如果有一條else if語句的表達式測試成功,那麼會忽略掉其他所有else if和else分支。

      ⑥如果出現多個if,隻有一個else的情形,else子句歸屬于最内層的if語句

 4.1.1、傳統用法

        val a = 10
        val b = 20
        var max_0: Int = a


        if (a > b) {
            max_0 = a
  
        } else {
            max_0 = b
        }


        println("----------------------------------")
        println("max_0:$max_0")
        println("----------------------------------")


        // Log
        --------------
        max_0:20
        --------------
  
           

 4.1.2、作為表達式

   var max_1 = if (a > b) a else b
   println("--------------")
   println("max_1:$max_1")
   println("--------------")


   //Log
   --------------
   max_1:20
   --------------
           

 4.1.3、作為代碼塊

   println("--------------")
   val max_2 = if (a > b) {
       println("Choose a")
       a
   } else {
       println("Choose b")
       b
   }


   println("max_2:$max_2")
   println("--------------")


   // Log  
   --------------
   Choose b
   max_2:20
   --------------

           

   if 作為代碼塊時,最後一行必須為該塊的傳回值.

   如果 if 表達式隻有一個分支, 或者分支的結果是 Unit , 它的值就是 Unit 。

 4.2、"when"

  when會對所有的分支進行檢查直到有一個條件滿足。 when 可以用做表達式或聲明。

 如果用作表達式的話,那麼滿足條件的分支就是總表達式。

 如果用做聲明,不滿足條件的分支的的的值會被忽略,隻保留滿足條件的分支,而且傳回的值也是最後一個表達式的值。

 4.2.1、傳統用法

        val x : Int = 10
        when (x) {
            9 -> println("x:${x + 10}")
            10 -> println("x:$x")
            else -> print("x:$x")
        } 
  
           

 4.2.2、分支條件一緻

        如果有分支可以用同樣的方式處理的話, 分支條件可以連在一起處理。

when (x) {
    0,1 -> print("x == 0 or x == 1")//同樣的方式處理
    else -> print("otherwise")
}
  
           

 4.2.3、使用任意表達式作為分支的條件  

when (x) {
    parseInt(s) -> print("s encode x")
    else -> print("s does not encode x")
}


when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}
           

 4.2.4、作為表達式

val hasPrefix = when (x) {
    is String -> x.startsWith("prefix")
    else -> false
}
           

 4.3、"for"

      for 循環通過任何提供的疊代器進行疊代。 文法如下:

 for (item in collection)
     print(item)
 
 //如果周遊list或者array可以通過索引進行疊代:
      
 for (i in array.indices)
     print(array[i])
 
 
           

 4.4、"while" 循環

 4.4.1、"while"語句:while語句在循環剛開始時,會計算一次布爾表達式的值,如果滿足條件,進入循環,

                   如果不滿足條件,将跳出循環。而在while語句的下一次疊代開始前會計算再一次布爾值,如此重複。

while (x > 0) {
    x--
} 
 
           

 4.4.2、"dowhile"語句:dowhile語句與while語句類似,唯一的差別是doWhile語句會至少執行一次,即便布爾表達式的第一次計算就是false。而while語句中,如果 布爾表達式的第一次計算的值是false,該循環不會執行。

 4.5、傳回與跳轉 Kotlin中有"return"、"break"、"continue"等三種傳回跳轉操作符。

 4.5.1、"return" ①指定一個方法傳回什麼值 ②導緻目前方法結束,并傳回傳回指定的值  

   
fun main(args: Array<String>) {
    println("testA:${testA(10)}")
    println("----------")
    println("testB:${testB(10)}")
}


fun testA(a : Int):Int{
    if (a > 0) {
        return -1
    } else {
        return 1
    }
}


fun testB(a : Int):Int{
    println("a:$a")
    if (a > 0) {
        return -1
    } else {
        return 1
    }
    a++
    print("a:$a")
}


// Log列印
testA:-1
----------
a:10
testB:-1
 
           

 4.5.2、"break" 結束最近的閉合循環,不執行循環中剩餘的語句  

     val arraysA = listOf("A", "B", "C", "D")
     val arraysB  = listOf(1,2,3,4)
     for (itemA in arraysA) {
         for (itemB in arraysB) {
             if (itemB > 2) {
                 break
             }
             println("itemB:$itemB")
         }


         if (itemA == "C") {
             break
         }
         println("itemA:$itemA")
     }


     // Log
     itemB:1
     itemB:2
     itemA:A
     itemB:1
     itemB:2
     itemA:B
     itemB:1
     itemB:2
           

   從Log列印可以看出,第一個break結束的是for (itemB in arraysB)這個循環,

而第二個break結束的是for (itemA in arraysA),它們的共通點就是結束都是距離它們最近的一個循環。

 4.5.3、"continue" 跳到最近的閉合循環的下一次循環

 val arraysA = listOf("A", "B", "C", "D")
   val arraysB  = listOf(1,2,3,4)


   for (itemA in arraysA) {
       var i : Int = 0
       for (itemB in arraysB) {
           i++
           if (itemB > 2) {
               continue
           }
           println("itemB:$itemB")
       }


       if (itemA == "C") {
           continue
       }
       println("i:$i")
       println("itemA:$itemA")
       println("---------")
   }


   // Log
   itemB:1
   itemB:2
   i:4
   itemA:A
   ---------
   itemB:1
   itemB:2
   i:4
   itemA:B
   ---------
   itemB:1
   itemB:2
   itemB:1
   itemB:2
   i:4
   itemA:D
   ---------   
           

   從上述Log上,可以清楚看到,兩個循環分别循環了四次,但是在碰到continue時,會跳出目前循環并執行下一次循環。

 4.6、标簽   在 Kotlin 中表達式可以添加标簽,标簽通過@結尾來表示,比如:[email protected],[email protected]

 [email protected] for (i in 1..100){
     //...
 }
           

 4.6.1、"break"和标簽

   val arraysA = listOf("A", "B", "C", "D")
   val arraysB  = listOf(1,2,3,4) 
   [email protected] for (itemA in arraysA) {
       var i : Int = 0
       for (itemB in arraysB) {
           i++
           if (itemB > 2) {
               [email protected]
           }


           println("itemB:$itemB")
       }


       println("i:$i")
       println("itemA:$itemA")
       println("---------")
   }


   // Log列印
   itemB:1
   itemB:2
           

從Log列印,第一個循環執行了一次,第二個循環執行了兩次,便跳出了封閉的循環。

意味着break跳到标簽後邊的表達式,并不再執行此表達式直接跳過,執行後邊的語句。

 4.6.2、"continue"和标簽

   val arraysA = listOf("A", "B", "C", "D")
   val arraysB  = listOf(1,2,3,4) 
[email protected] for (itemA in arraysA) {
    var i : Int = 0
    for (itemB in arraysB) {
        i++
        if (itemB > 2) {
            [email protected]
        }


        println("itemB:$itemB")
    }


    println("i:$i")
    println("itemA:$itemA")
    println("---------")
}


// Log列印
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
itemB:1
itemB:2
 
           

   之前說過,continue是跳到最近的閉合循環的下一次循環,但是加上标簽以後,直接跳轉到了第一個循環,也就是for (itemA in arraysA),

并沒有執行最近的閉合循環的下一次循環。意味着continue直接跳轉到标簽後面的語句并執行。

 4.6.3、"return"和标簽  

   
val ints = listOf(0, 1, 2, 3)
fun main(args: Array<String>) {
    foo()
}
fun foo() {
    ints.forEach {
        if (it ==0) [email protected]
        println(it)
    }
}
// Log列印
1
2
3
           

從Log列印可以看出,return會跳轉到标簽後邊的表達式處,并執行該表達式。

 4.6.4、命名函數自動定義标簽

        foo outer() {
            foo inner() {
                [email protected]
            }
        } 
           

 4.6.5、作用域

      
        val ints = listOf(0, 1, 2, 3)
        fun main(args: Array<String>) {
            [email protected]
            foo()


        }


        fun foo() {
            ints.forEach {
                if (it ==0) [email protected]
                println(it)
            }
//return @list//這麼調用會報錯,會提示“Unresolved reference:@list”
        } 
           

        從作用域來看,标簽和變量是一緻的,都有相對應的作用域。在main方法裡面定義了一個标簽[email protected],在foo方法裡面調用時,

提示“Unresolved reference:@list”,意味着list标簽的作用域應該在main方法裡,在foo方法裡并不能夠調用。 

感謝

https://github.com/huanglizhuo/kotlin-in-chinese

http://blog.csdn.net/IO_Field/article/details/52842596

http://blog.csdn.net/jhj_24/article/details/53887820