Kotlin知識概括(一) —— 基礎語法

前序

        在19年的Google I/O大會上,Kotlin 成爲 Android 開發首選語言。而著名的OkHttp 已經開始用 Kotlin 進行重寫工做。是時候經過寫博客概括來鞏固Kotlin基礎知識。java

(一)、語法上的變動

  • 建立對象不須要new關鍵字
  • 語句不須要;結尾,加;也無所謂
  • 變量類型後置,即變量名在前,變量類型在後。例如 str:String
  • 使用 println() 替代 System.out.println()

(二)、定義變量

        Kotlin中使用val關鍵字聲明常量(即變量初始化以後不可再次賦值),var關鍵字聲明變量。android

變量定義時能夠不顯示指定類型,編譯器會根據其初始化器的類型進行推斷。數組

//自動推斷出 `Int` 類型
var daqi = 1
//能夠顯式地指定變量的類型
val a :String = "daqi"
//若是變量沒有初始化器,須要顯式地指定它的類型
val c: Int
c = 3  
複製代碼

當編譯器能確保val變量只有惟一一條初始化語句會被執行,能夠根據條件對它初始化不一樣的值。安全

val daqi:String
var isChange = true
if (isChange){
   daqi = "1"
}else{
   daqi = "2"
}
複製代碼

val變量的引用自身是不可變的,可是它指向的對象是可變的。bash

val languages = arrayListOf("Java")
languages.add("Kotlin")
複製代碼

var 關鍵字容許變量改變本身的值,但不能改變本身的類型。ide

var daqi = 1
//編譯不經過
daqi = ""
複製代碼

(三)、定義函數 Kotlin 中使用 fun 關鍵字聲明函數。 完整的函數定義:函數

修飾符(默認public)+ fun + 方法名 + (參數列表) :返回值 {
        函數體
}
複製代碼

public fun daqi(name:String):String {
}
複製代碼

表達式函數體

        當單個表達式構成完整的函數體時,能夠直接去掉 {} 和 return 語句,函數的返回值類型編譯器也會自動推斷。這種函數就是表達式函數。工具

fun sum(a: Int, b: Int) = a + b
複製代碼

語句和表達式的區別在於:post

  • 表達式有值,而且能做爲另外一個表達式的一部分使用;
  • 語句老是包圍着它的代碼塊中的頂層元素,而且沒有本身的值。

        在 Java 中,全部的控制結構都是語句。而在 Kotlin 中,除了循環( for, do 和 do/while )之外大多數控制結構都是表達式(例如:if、 when 以及 try 屬於表達式)ui

         表達式函數不光用在些簡單的單行函數中 ,也能夠用在對更復雜的單個表達式求值的函數中。

fun max(a: Int, b: Int ) = if (a > b) a else b
複製代碼

無返回值的函數

相似Java的返回值類型爲void的函數

fun daqi():Unit{
}
複製代碼

可省略Unit類型

fun daqi(){
}
複製代碼

(三)、字符串模板

在 Java 中,當須要打印變量描述和其值時,每每以下打印:

String str = "daqi";
System.out.println("str = " + str);
複製代碼

    Kotlin支持字符串模板,能夠在字符串中引用局部變量,但須要在變量名前加上$。表達式會進行靜態檢查, 若是$引用一個不存在的變量,代碼不會編譯經過。

val str = "daqi"
printlin("str = $str")
複製代碼

$不只限於引用於簡單的變量名稱,還能夠引用更復雜的表達式。

val daqi = intArrayOf(1,2,3)
println("${daqi[0]}")
複製代碼

在$引用的表達式內(即花括號{}中)能夠直接嵌套雙引號

println("daqi的第一個元素: ${if(daqi.size > 0) daqi[0] else "null"}")
複製代碼

當須要打印$符號時,能夠對其進行轉義,或者利用表達式對其進行打印:

//打印結果爲:$str
val str = "daqi"
println("\$str")
println(${'$'}daqi)
複製代碼

(四)、類和屬性

在java中定義一個簡單類:

public class Person{
    private final String name;
    
    public Person(String name){
        this.name = name;
    }
    
    public String getName(){
    	return name;
    }
}
複製代碼

用Kotlin寫的Person類(默認public修飾)

class Person(val name:String)
複製代碼

延伸:若想知道Kotlin對應的具體Java實現,能夠經過idea的工具,對Kotlin文件進行反編譯:

    Tools ->Kotlin -> Show Kotlin Bytecode -> 右側彈出字節碼框 ->左上角 Decompile按鈕

總體基本和Java類類似,可是該類被定義爲final類,即太監類,不可被繼承。

setter 和 getter

    在Kotlin中,當你聲明屬性的時候,也就聲明瞭對應的訪問器(即get和set)

    val屬性只有一個getter,var屬性既有 getter 和 setter。 聲明一個屬性的完整語法:

var <propertyName>[: <PropertyType>] [= <property_initializer>]
    [<getter>]
    [<setter>]
複製代碼

    其中,初始化器,getter 和 setter 都是可選的。若是類型能夠從初始化器或者getter 返回值中推斷出來,也能夠省略。 訪問器的默認實現很是簡單,即對對應變量的返回和更改。

當須要在值被訪問或修改時提供額外的邏輯,能夠經過自定義getter和setter

自定義getter

在Kotlin中的實現

class Rectangle(val height:Int,val width:Int){
    val isSquare:Boolean
        get(){
        	return height == width
    	}
}
複製代碼

對應的Java實現:

自定義setter

在Kotlin中實現:

class Rectangle(val height:Int,val width:Int){
    var isSquare:Boolean = false
        set(value) {
            field = value
        }
}
複製代碼

在setter方法中,使用特殊的標識符field來訪問支持字段(幕後字段)的值。具體幕後字段後面再說。

注意:

    Kolin中,名稱以is開頭的變量。轉換成對應的Java get 和 set 方法時,getter不會添加任何的前準,setter名稱中的is會被替換成set。

class Person(
    var isDaqi:Boolean = false
)
複製代碼

該對象在Java中的訪問器爲:

(五)、迭代

Kotlin中 while 和 do-while循環,其語法與Java的基本沒區別。

而for循環僅以一種形式存在,和for-each差很少。但用 in 取代了 :

fun iterationArray(args:Array<String>){
    for (str in args) {

    }
}
複製代碼

    for循環還能夠遍歷區間。區間本質上是兩個值之間的間隔。使用..運算符表示區間。

    Kotlin中的區間是閉合區間,即結束值也是區間的一部分。而區間默認迭代步長爲1。

val oneToTen = 1..10
複製代碼

    能夠經過step關鍵字修改步長。遍歷時,i變量其增加幅度將變爲2,即每次迭代時都會自增2。

for(i in 0..100 step 2){
}
複製代碼

若是想要一個半閉合區間,即結束值不屬於區間的一部分,可使用until關鍵字,

val oneToNine = 1 until 10
複製代碼

若是須要一個倒序的區間,可使用downTo關鍵字

val tenToOne = 10 downTo 1
複製代碼

此時,將從10一直遞減到1進行循環。downTo表示的區間也是一個閉合區間。

若是想實現普通for循環同樣,對數據索引進行循環,可使用數組的indices變量

for (i in args.indices) {
    println(args[i])
}
複製代碼

(六)、if表達式

在Kotlin中,if是一個表達式,即它會返回一個值。

if的分支爲代碼塊時,最後的表達式將做爲該代碼塊的值:

val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}
複製代碼

(七)、when表達式

Kotlin中的when,對應的是Java中的switch,但比起更增強大。

    when 將它的參數與全部的分支條件按順序比較,直到某個分支知足條件,執行其分支對應的代碼。當多分支須要用相同的方式處理時,能夠把其放在一塊兒,用逗號分隔。

    當when做爲表達式使用時,必須有 else 分支, 除非編譯器檢測出全部的可能狀況都已經被覆蓋。(例如枚舉類)

when (x) {
    0, 1 -> print("x == 0 or x == 1")
       2 -> print("x == 2")
    else -> print("otherwise")
}
複製代碼

有沒有發現,沒有了那繁瑣的case和break!!

    when的參數無關緊要,而且無限制類型!並且能夠用任意表達式做爲分支條件。(switch要求必須使用常量做爲分支條件~)

    when做爲表達式函數的的函數體,直接使用函數的參數,自身並沒有設置參數。並在條件語句中使用in或者!in 判斷一個變量是否在區間或者集合中。

fun daqi(num:Int,intArray: IntArray) = when{
    num in 1..10 -> "1~10"
    num !in intArray -> "no in Array"
    else -> "other"
}
複製代碼

when 也能夠用來取代 if-else if鏈.

fun daqi(num:Int) = when{
    num < 0 -> "小於0"
    num >0 && num < 10 -> "1..10"
    else -> "other"
}
複製代碼

    is能夠檢查一個變量是不是某種類型,再配合智能轉換(檢查過某個變量的類型後,再也不須要再轉換它,直接能夠把它看成檢查過的類型使用)能夠很方便的對進行類型安全操做。

//Any相似於Java的Object
fun daqi(num:Any) = when(num){
    is String -> {
        //此時num已經爲String類型
        println("該變量類型爲String,獲取其長度")
        println(num.length)
    }
    is Int -> {
        //此時num已經爲Int類型
        println("該變量類型爲Int,將其與10進行對比")
            num.rangeTo(10)
    }
    else -> "other"
}
複製代碼

(八)、Kotlin中的異常

    Kotlin的異常處理與Java相似。當拋出異常時,不須要使用new關鍵字建立異常實例。

var daqi:String? = null
if (daqi == null){
    throw NullPointerException("daqi is null")
}
複製代碼

    try也能夠做爲表達式,將其賦值給變量。當代碼執行正常,則try代碼塊中最後一個表達式做爲結果,若是捕獲到異常,對應catch代碼塊中最後一個表達式做爲結果。finally 塊中的內容不會影響表達式的結果。

fun readNumber(reader:BufferedReader):Int? = try{
    Integer.parseInt(reader.readLine())
}catch(e:NumberFormatException){
    null
}catch (e:NullPointerException){
    null
}finally {
    reader.close()
}
複製代碼

能夠有0到多個 catch 塊。finally 塊能夠省略。 可是 catch 與 finally 塊至少應該存在一個。

(九)、枚舉

    kotlin中用兩個關鍵字enum和class聲明枚舉類。enum是一個軟關鍵字,只有當它出如今class前面時纔有特殊的意義。

聲明普通枚舉類:

enum class Color{
    RED,BLUE
}
複製代碼

聲明帶屬性的枚舉類:

enum class Color(val r:Int,val g:Int,val b:Int){
    RED(255,0,0),BLUE(0,0,255);
    fun rgb = (r * 256 + g) * 256 + b
}
複製代碼

若是在枚舉類型中定義任何方法,須要使用分號;把枚舉常量列表和方法定義分開。

參考資料:

android Kotlin系列:

Kotlin知識概括(一) —— 基礎語法

Kotlin知識概括(二) —— 讓函數更好調用

Kotlin知識概括(三) —— 頂層成員與擴展

Kotlin知識概括(四) —— 接口和類

Kotlin知識概括(五) —— Lambda

Kotlin知識概括(六) —— 類型系統

Kotlin知識概括(七) —— 集合

Kotlin知識概括(八) —— 序列

Kotlin知識概括(九) —— 約定

Kotlin知識概括(十) —— 委託

Kotlin知識概括(十一) —— 高階函數

Kotlin知識概括(十二) —— 泛型

Kotlin知識概括(十三) —— 註解

Kotlin知識概括(十四) —— 反射

相關文章
相關標籤/搜索