天天看点

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