Kotlin 學習(2) Kotlin基礎

weixin_34234823發表於2018-01-31

2.1 函式

2.1.1 函式的宣告

關鍵字(fun) 函式名 引數列表 返回值

  • 無返回值的函式
 fun main(array: Array<String>){
     
 }
  • 有返回值的函式
fun max (a:Int,b:Int) :Int{
    
    return if (a>b) a else b
  
}
2.1.2 表示式體函式
fun max(a: Int, b: Int) = if (a > b) a else b
  • 常規的把函式體寫在有花括號的函式叫做:程式碼塊體函式
  • Kotlin中函式可以直接返回一個表示式,省略掉花括號的return語句。這就叫表示式體函式
  • 表示式體函式可以不宣告返回型別,編譯期可以分析表示式返回值的型別,將其作為函式的返回值。這叫**型別推導 **

注意

Kotlin中,如果函式最後一個引數是lamada表示式,這個表示式可以放到括號外面。如果函式引數只有一個lamda引數,則括號可以省略,具體如下

  fun main(array: Array<String>){
    
    //1 常規寫法
    array.map({})
    //2 最後一引數為 lamda表示式時,可以這樣寫
    array.map(){

    }
    //3 如果函式只有lamda表示式一個引數,括號可以省略
    array.map {
      
    }
}
2.1.3 函式的其他寫法
 var i = {a:Int,b:Int -> a+b}
 var j:(Int,Int)->Int = {x,y->x+y}
2.1.4 函式的預設引數和具名引數
  • 預設引數:在函式的引數列表中可以為某個引數指定預設值
  • 具名引數:在呼叫函式時,如果預設引數不傳值。則其他引數要要指明其引數名稱,即具名引數

val Pi = 3.14159f //預設引數
fun getArea(PI: Float = Pi, radius: Float): Float {

    return PI * radius * radius
}

fun main(args: Array<String>) {
    println(getArea(radius = 2.5f))
}

2.2 變數

2.2.1 變數的宣告

關鍵字(val,var) 變數名稱 【變數型別】 變數的值

  • 如果不指定變數的型別,編譯期會將初始化值的型別作為變數的型別

      val name = "m1Ku"
      val length :Int = 1
      val mWidth = 23.8
    

  • 如果變數沒有初始化值,則必須顯式的指明其型別

    val age:Int
    age = 28
    

可變變數和不可變變數

  • val(value) - 不可變引用。使用val宣告的變數不能在初始化之後再賦值。相當於Javafinal變數

  • var(variable) - 可變引用。這種變數的值是可以改變的。相當於普通的Java變數

      //val不可變變數,重複賦值。會提示val cannot be reassigned
         val age = 29
         age = 28
    
    //var可變變數,可以重新賦值
        var radius = 2.6
        radius = 3.5
    
2.2.2 字串模板

字串模板:使用字串模板可以在字串中使用區域性變數或者表示式的值。

  • 引用區域性變數

    //變數名前加上 $符號
    val name = "m1Ku"
    println("My name is $name!")
    >>> My name is m1Ku!
    
  • 引用表示式

    //引用表示式時,只需要將表示式用 花括號括起來
    println("This Array is ${if (array.isNotEmpty()) "not empty" else "empty"}!")
    >>> This Array is empty!
    
    println("The first element of array is ${array[0]}!")
    >>> The first element of array is test!
    

2.3 類和屬性

2.3.1 屬性

屬性值由關鍵字valvar宣告。val宣告的屬性值是隻讀的,var宣告的屬性值是可變的。

class Animal(){
    val name:String = ""
    val sex:Boolean = false
    var weight:Double = 0.0
    private val speed:Int = 0
}
  • 宣告的屬性必須要初始化,否則編譯會報錯
  • 預設是被public修飾符修飾,如果要禁止其他類訪問,可以使用private修飾符修飾
  • 編譯期自動生成訪問器,其中var屬性既有getter也有setterval屬性只有getter訪問器
屬性的宣告

雖然編譯器可以預設生成訪問器,但是上面屬性定義並不是完整的屬性宣告。

完整的屬性宣告如下:

關鍵字 屬性名:屬性型別 初始化值

【getter】

【setter】

  • 如下,程式碼中宣告瞭isSquare這個屬性。並且自定義了其getter訪問器
class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() = height == width
}

2.3.2 Kotlin原始碼佈局,目錄和包

  • Kotlin中也有Java中包的概念,每個檔案的開頭都以package語句開頭,檔案中定義的函式類和屬性都在包中

  • Kotlin不區分匯入的是類還是函式,它允許使用import關鍵字匯入任何種類的宣告

  • Kotlin中可以把多個類放在同一個檔案中,檔案的名字可以隨意選擇

2.4 表示和處理選擇:列舉和“when”

2.4.1宣告列舉類

Kotlin中列舉類用 enum class宣告

enum class Color{
    RED,ORANGE,YELLOW,GREEN,BLUE,INDIGO,VIOLET
}

KotlinJava一樣,可以給列舉宣告屬性和方法。如果宣告瞭列舉常量的屬性,則在宣告每個列舉常量時,必須要提供該常量的屬性值。如果給列舉類定義方法,需要用分號將常量列表和方法分隔開

enum class Color(val r: Int, val g: Int, val b: Int) {
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 0),
    BLUE(0, 0, 255),
    INDIGO(75, 0, 130),
    VIOLET(238, 130, 238);

    fun rgb() = (r * 256 + g) * 256 + b
}

2.4.2 使用“when”處理列舉類

when是一個有返回值的表示式,因此也可以寫成一個直接返回when表示式的表示式體函式

fun getColorName(color: Color)=
        when(color){
            Color.RED -> "Richard"
            Color.ORANGE -> "Of"
            Color.YELLOW -> "York"
            Color.BLUE,Color.GREEN -> "這是多個值合併的分支"
            else -> "i dont know this color"
        }

每個分支上不需要寫break語句。可以把多個值合併到一個分支中,只需要用逗號分開

2.4.3 在“when”結構中使用任意物件

Javaswitch必須使用常量作為分支條件,而Kotlinwhen可以使用任意物件作為分支條件

fun mix(c1:Color,c2: Color) : Color{
    when(setOf(c1,c2)){
        setOf(Color.RED,Color.YELLOW) -> return Color.ORANGE
        setOf(Color.YELLOW,Color.BLUE) -> return Color.GREEN
        else -> throw Exception("抱歉,這兩種顏色不能混合")
    }
}

>>println(mix(Color.RED,Color.YELLOW))
  ORANGE
>>println(mix(Color.GREEN,Color.BLUE))
  Exception in thread "main" java.lang.Exception: 抱歉,這兩種顏色不能混合

2.4.4 使用不帶引數的”when“

如果不給when表示式提供引數,分支條件就是任意的布林表示式。這樣寫不會建立額外的物件,但程式碼可讀性變差了

fun mixColor(c1: Color, c2: Color) {
    when {
        (c1 == Color.RED && c2 == Color.YELLOW)
                || (c1 == Color.YELLOW && c2 == Color.RED) -> Color.ORANGE
        (c1 == Color.YELLOW && c2 == Color.BLUE)
                || (c2 == Color.YELLOW && c1 == Color.BLUE) -> Color.GREEN
        else -> throw Exception("抱歉,這兩種顏色不能混合")
    }
}

2.4.5 智慧轉換:合併型別檢查和轉換

Kotlin中使用is判斷一個變數是否是某個型別,這類似於在Java中使用instance of檢查變數型別,Java中判斷過型別變數後,還要顯示的進行型別轉換。但在Kotlin中,當使用is檢查過變數型別後,我們不需要再顯式的轉換型別,因為編譯期已經為我們執行了型別轉換,這叫做智慧轉換

interface Expr
//定義num物件 實現Expr介面
class Num(val value: Int) : Expr
//定義Sum物件 實現Expr介面
class Sum(val left: Expr, val right: Expr) : Expr

//定義方法計算傳入物件的值
fun eval(e:Expr):Int{
    //is檢查某一個變數是否時某種型別
    if (e is Num){
        val n = e as Num //冗餘程式碼kotlin中不需要顯示轉換
        return n.value
    }
    if (e is Sum){
        val m = e as Sum
        return eval(e.left) + eval(e.right)
    }
    throw IllegalArgumentException("未知表示式")
}

as關鍵字是顯式的型別轉換,然而在上述的程式中是多餘的,因為我們已經用is檢查過它的型別了

2.4.6 用“when”代替“if”

when表示式不限於檢查值是否相等,如下程式也可以檢查實參的資料型別

fun evalWithWhen(e: Expr): Int =
        when (e) {
            is Num -> e.value
            is Sum -> eval(e.left) + eval(e.right)
            else ->
                throw IllegalArgumentException("未知表示式")
        }

2.4.7 程式碼塊也可以作為if和when的分支

ifwhen都可以使用程式碼塊作為分支體,程式碼塊中最後一個表示式就是結果

fun evalWithLog(e:Expr):Int =
        when(e){
            is Num ->{
                println("num = ${e.value}")
                e.value
            }
            is Sum ->{
                val m = evalWithLog(e.left)
                val n = evalWithLog(e.right)
                println("Sum = m + n=  ${m + n}")
                m + n
            }
            else ->
                throw IllegalArgumentException("未知表示式")
        }

2.5 區間和迴圈

2.5.1 區間

區間:區間是兩個值之間的間隔,這兩個值通常是數字:一個是起始值,一個是結束值。使用.. 運算子來表示。

 //閉區間
 var nums:IntRange = 1..16
//前閉後開區間
 var nums :IntRange = 1 until 16
2.5.2 迴圈
  • whiledo while 迴圈與在java中的使用方式一致
  • kotlin中沒有java中那種普通的for迴圈,迴圈使用如下for ...in迴圈
 //使用in關鍵字
for (num in nums) {
        println(num)
    }
//step表示步長為2取值
 for (num in nums step 2) {
        println(num)
    }
>> 輸出為 1 3 5 7 ....
  • map的賦值和遍歷
    //定義map集合
    var maps = TreeMap<Char,Int>()
    for (c in 'A'..'F'){
        //給map元素賦值
        maps[c] = c.toInt()
    }
    //遍歷map集合
    for ((key,value) in maps) {
        println("$key $value")
    }
  • in運算子可以用來檢查一個值是否在區間中
fun judge(c:Char) = when(c){
    in '0'..'9' ->"this is a digit"
    in 'a'..'z' ->"this is a letter"
    else -> "this is nothing"
}

2.6 Kotlin中的異常

Kotlin的異常處理和Java以及其他語言的處理方式相似。一個函式可以正常結束,也可以在出現錯誤的情況下丟擲異常。方法的呼叫者能捕獲這個異常並處理它;如果沒有被處理,異常會沿著棧再次丟擲。

  • Kotlin丟擲異常使用throw關鍵字,但不必使用new關鍵字來建立異常的例項

    fun checkNum(num: Int) {
        if (num in 1..100)
            println("$num 是一個在1到100之間的數字")
        else
            throw IllegalArgumentException("輸入的數字必須在1到100之間")
    }
    
  • Kotlinthrow結構是一個表示式,能作為另一個表示式的一部分使用

    fun checkNum2(num:Int):Int{
        var result =
                if (num in 1..100)
                    num
                else
                    throw IllegalArgumentException("輸入的數字必須在1到100之間")
        return result
    }
    

    上面程式中,如果程式執行正常result的值將被num初始化。否則會丟擲異常,result也不會被初始化

2.6.1 "try" "catch" 和 "finally"

Kotlin中使用帶有catchfinally的子句的try結構如下所示

fun readNumber(reader: BufferedReader): Int? {
    try {
        val line = reader.readLine()
        return Integer.parseInt(line)
    } catch (e: NumberFormatException) {
        return null
    } finally {
        reader.close()
    }
}

Java中的寫法如下

public int readNumber(BufferedReader reader) throws IOException{
        try {
            String str = reader.readLine();
           return Integer.parseInt(str);
        }
        catch (NumberFormatException e){
            return 0;
        }
        finally {
            reader.close();
        }
    }
  • Kotlin程式碼沒有出現throw子句,而java中必須顯式在函式宣告上寫上throws IOException,因為IOException是一個受檢異常,java中必須顯式的處理,宣告函式能丟擲所有受檢異常
  • Kotlin不區分受檢和未受檢異常。不用指定函式丟擲的異常,也可以不處理異常

2.6.2 try作為表示式

Kotlin中的try``就像ifwhen`一樣,引入了一個表示式,可以把它的值賦給一個變數。需要用大括號將主體語句括起來。如果主體語句包含多個表示式,那麼整個try表示式的值就是最後一個表示式的值

fun readNum(reader: BufferedReader){
    var result =
            try {
                Integer.parseInt(reader.readLine())
            }
            catch (e:NumberFormatException){
                null
            }
    println(result)
}
readNum(BufferedReader(StringReader("33")))
>> 33
readNum(BufferedReader(StringReader("wewewe")))
>> null

相關文章