Kotlin 與 Java 比較 | Kotlin 生態、入門 | Kotlin 特點、基礎

Kotlin 與 Java 比較 | Kotlin 生態、入門 | Kotlin 特點、基礎

Overview of Content

這篇文章旨在為那些已經熟悉 Java 語言的讀者提供對 Kotlin 的了解。

我們將探討 Kotlin 的基本特性、與 JVM 虛擬機的關聯,以及它在軟體開發領域中的發展趨勢。

文章首先介紹Kotlin的基礎知識,包括變量宣告、判斷語句如if/else和when的使用,以及循環和區間的語法糖。接著,我們深入探討 Kotlin 與 Java 之間的基本差異,使讀者能夠更容易地轉換在 Java 中的知識和技能到 Kotlin 上。

此外,我們將簡要介紹Kotlin在多平台生態圈中的角色,以及如何在項目中有效地使用 tag 標籤。透過本文,讀者將能夠建立起對Kotlin語言的基礎理解,並掌握在實際項目中應用這一現代語言的能力。

如有引用參考本文章請詳註出處,感謝 😀


Kotlin 語言簡介

Kotlin 是由 JetBrains 公司 開發與設計,2011 就已釋出第一個版本,並在 2012 年將其開源,2016 年 Kotlin 發布了正式 1.0 版,並在自家的 IDE 開發工具 IntelliJIDEA 加入該語言

Kotlin 是基於 JVM 的語言,所以它可以很好的跟 Java 相容,並且它不只可以開發 Android App 甚至可以開發後端服務、編譯成 JavaScript 程式

● Kotlin 是 JetBrains 團隊開發出來的程式語言,其取名也源自於 聖彼得堡附近的 柯特林島 (俄羅斯附近)

Kotlin 特性

● Kotlin 語言有以下幾個高級語言特性 (收集了各個語言的專長 (Python, Java, C#, JavaScript, Scala, Groovy... 等等)

A. 函數(方法):高階函數 & Lambda 表達式

B. 防止 NPE:空類型,Elvis 表達式,Scope Function

C. Lazy loading:懶加載,在需要時才創建資源,並且 Lazy loading 默認執行序(線程)安全

D. DSL 編程:如同 Groovy 一樣的 DSL 編程

E. Thread 管理:以往在 Java Multi Thread 中我們常常會耗費 CPU 時間來做上下文切換,而 在 Kotlin 中,有開發 Coroutine library 幫助我們做快速的上下文切換

● 關於 Kotlin 更多 Coroutine 的使用請看 Coroutine - 協程

Kotlin & JVM 虛擬機

● 在 Android Java 有使用版權問題(甲骨文、Google十年恩怨落幕!90億美元Java案大翻盤),而 JVM 並沒有版權問題,這也就是為何 Kotlin 可以編譯出 Android 能夠接受的語言,其原因主要是因為 JVM 透過翻譯字節碼(Byte code)來運行程式而 Java、Kotlin 都是翻譯型語言,透過 JVM 翻譯過後都是相同的

這是基於平台開發語言抽象化的優點,讓語言本身面向的是 JVM 虛擬機,只要編譯出 JVM 可識別的 Byte code 就可以在不同平台上運行

翻譯型 & 編譯型 ?

編譯型:典型的編譯型語言像是 C、C 都屬於編譯型語言,它會針對當前的 CPU 編譯成對應的二進制文件

翻譯型:需要翻譯成第三方能夠看得懂的語言,再由第三方翻譯成二進制碼給 CPU 做程式運行,就像是 Java、Python 語言

兩者來說翻譯型語言的共通性較強,但相對的它的效率較低,它的特點剛好與編譯型語言相反

編譯概念圖如下


Kotlin 發展

Kotlin 的發展以目前來看,是作為 Java 的輔助、加強(可從上面的輔助看出),不會完全的取代 Java

Kotlin 生態圈:多平台

● Kotlin 目前已經是 Android App 開發的主流語言(官方推薦, Kotlin and Android),除了一動端之外後端也可以很好的使用 Kotlin(後端開發常使用的 Spring 也推薦 Kotlin)

● Kotlin 不只可以編譯成 Java 語言,也可以直接編譯成 Binary code & Js code,對於跨平台編譯也佔據一席之地(kotlin multiplatform

● Kotlin 支援多平台 & 語言,其中包括 JVM, Android, iOS, JavaScript, Linux, Windows, Mac 甚至嵌入式 STM32

● JetBrains 提供多平台開發 Kotlin Multiplatform Mobile (KMM)


Kotlin 與 Java 基礎差異

● 程式執行主要分為三種方式執行(以程式結構化的概念去思考,分為三點去討論!)

A. 順序語句 : 如同 Java 是由上往下單句執行

B. 條件語句 : 條件判斷 if/elseKotlin 沒有 switch 關鍵字,並使用了 when 取代

C. 循環語句 : for/while 條件循環

Kotlin 變量宣告

● Java 中要定義一個遍量必須聲明變量的型態 (int a = 20),Kotlin 宣告時只允許在變量前聲明 varval 兩個關鍵字,並且有自動推倒的特性

kotlin 變量關鍵字與 Java 比對舉例
var該變量可改變var A
val如同在變量前使用 final 描述,說明該變量是不可改變的val B

● 先說明幾個特性 1. Kotlin 結語不需使用 ; 分號2. Kotlni 類型可以自動推倒 (也可以自行設定)


// 包名不建議大寫開頭
package class_1

/**
 * 變數 & 型態
 * 變數皆使用 var、val 定義
 * var : 可變參數
 * val : 不可變參數,其功能是為了解決 Java 中 final 不常被使用的問題
 */
fun main() {
    println("Hello Kotlin!")    // 結束不須分號

    var a = 10
    a = 15
    // a = "Boy";  Err: var 推導後類型不可變
    println("a = $a");

    val b = 20
    // b = 25      Err: val 描述後不可再賦值, Val cannot be reassigned
    println("b = $b");

    var c : Int = 30      // ':' 類型指定
    c = 33
    println("c = $c");

    var d : Short = 1     // Kotlin 完全秉棄了 Java 的基礎類型,"全部皆為對象",基礎數據類型全部大寫
    d = 11
    println("d = $d");
}

● 關鍵字、自動推倒,要注意幾點:

A. var 類型推導完成後,不可再賦予其他類型

B. val 必須賦予值,並且不能再對其變量進行更改,否則編譯器會提是 Val cannot be reassigned 錯誤

C. 自動推導並非每次都有用,若是我們對一個變量延遲賦值,Kotlin 就無法自動推倒其類型,這時可以使用 : 指定


// lateinit 延遲初始化,就必須指定參數類型

lateinit var name: String

D. Kotlin 內所的事物皆為對象,也就是 沒有基礎數據類型 (其實也就是將 Java 每一個數據類型開頭改為大寫)

Java 基礎數據類型Kotlin 對象數據類型
booleanBoolean
charChar
byteBoolean
shortShort
intInt
longLong
floatFloat
doubleDouble

--實作結果--

為何設計 val 關鍵字

val 的設計是為了解決 Java 中 final 描述詞沒有被正當使用的情況;一般來說 類、變量若是沒有被使用應該都宣告為 final,以免被誤用,這是一個好習慣

Kotlin 判斷語句 if/else & when

● 以下會先說 if 與 Java 不同的使用地方,其最大的不同在於 Kotlin 的 if 可以直接返回數值,並且不需要 return 關鍵字

when 作為取代 switch 的關鍵字,並且 Kotlin 對其功能進行了拓展,可以搭配 is 使用在類的判斷相當於 java instanceof (取代 case,並 省略了 break 關鍵字),並且最後使用 else (取代 default)

A. if/else 判斷


// Kotlin's if 可使用如同 Java's if
fun useIf(n1: Int, n2: Int) : String {
    var result = ""
    if (n1 > n2) {
        result = "$n1 is Bigger"
    } else {
        result = "$n2 is Bigger"
    }
    return result
}

// Kotlin's if 可以有返回值!!
// 該返回值在代碼中的最後一行 (不須 return
fun useIfDiff(n1: Int, n2: Int) : String {
    return if (n1 > n2) {
        "$n1 is Bigger"
    } else {
        return "$n2 is Bigger"  // return 可有可無
    }
}

fun useIfSimple(n1: Int, n2: Int) = if (n1 > n2) {
    "$n1 is Bigger"
} else {
    "$n2 is Bigger"  // return 不可以用在 = 符號
}

B. when 代替 switch

when 語句如同 if 是可以有返回值


fun useWhenSimple(id: Int) = when(id) {
    1 -> "A"
    2 -> {  // 超過一行時使用大括號
        "B"
    }
    3 -> "C"
    else -> "Non"   // like default
}

// when 可以配合 is 一起使用,相當於 Java 的 instanceof
fun useIs(id: Number) : Unit = when(id) {
    is Int -> println("Params is Int")
    is Double -> println("Params is Double")
    is Float -> println("Params is Float")
    else -> println("Cannot decide Type")
}

// 若要直接使用參數判斷,when 就不需要括弧,並且可以 對關鍵字進行操作
fun useWhenWithParams(id: Number) = when {
    id is Byte -> println("Params is Int")
    id == 11 -> println("Params is 11")
    id == 11.1 -> println("Params is 11.1")
    id.toFloat() == 1.0f -> {
        println("Params is 1.0f")
    }
    else -> println("Cannot decide Type")
}

符號在 Java 中是用來判斷兩個內存地址是否相同,而 Kotlin 符號則是判斷對象、字串是否相同,相當於 equals 的方法

功能Java 關鍵字Kotlin 關鍵字
對象是否相等 (內容)equals==
內存(記憶體)地址是否相等=====

package class_1

fun main() {
    val a : String = "Hello"
    val b : String = String(StringBuffer("Hello"))

    println("a.equals(b): ${a.equals(b)}")
    println("a == b: ${a == b}")
    println("a === b: ${a === b}")
}

C. 測試順序語句、條件語句、循環語句


package class_1

/**
 * 程式的運營主要有三種型語句
 * 1. 順序語句  (執行程式的順序
 * 2. 條件語句  (if/else、when
 * 3. 循環語句  (for、while
 */
fun main() {
    var r = useIf(11, 2)
    println("Answer: $r")

    r = useIfDiff(11, 22)
    println("Answer: $r")

    r = useIfSimple(33, 22)
    println("Answer: $r")
    
    // --------------------------------------------
    r = useWhenSimple(3)
    println("When(id): $r")

    useIs(12.3f)

    useWhenWithParams(11)

    useWhenWithParams(1.0)

}

循環 & 區間 - 語法糖

● Kotlin 語言的特色之一,就是它有提供一系列優秀的「語法糖」,可以 有利於開發速度、可讀性!以下是 Kotlin 常用的 循環 & 區間 的關鍵字

關鍵字(符號)功能
until同樣是個區間,但是不包含最後一個元素 (左閉右開)
in判斷是否符合在區間內,會配合著 .. 一起使用 (類似 Python)
..區間,包含最後一個數字 (until 則不包含)
step前進的數量
downTo前面都是升序,downTo 則是降序讀取

/**
 * 循環: Kotlin 也提供 for & while
 * while 與 Java、C、C++ 相同
 * for-i 轉為 foreach,並大幅增強改變為 for-in
 *
 * 區間: 使用關鍵字 `..` 可以表示數值的區間 (小到大)
 * 用數學的表達方式就是 [0, 10]
 */
fun main() {
    println("3 in 0..10: ${3 in 0..10}")
    
    // 以下如同 [0, 2, 4, 6, 8. 10]
    println("3 in 0..10 step 2: ${3 in 0..10 step 2}")    // false
    
    // 以下如同 [0, 3, 6, 9]
    println("3 in 0..10 step 3: ${3 in 0..10 step 3}")    // true
    
    // 以下如同 [10, 7, 4, 1]
    println("4 in 10 downTo 0 step 3: ${4 in 10 downTo 0 step 3}")    // true

    useForIn()
    useForInStep()
    useForInUntil()
    useForInDownTo()
}

fun useForIn() {
    for (i in 0 .. 5) {
        println("$i")
    }
}

fun useForInStep() {
    for (i in 0 .. 5 step 2) {  // 一次前進 2
        println("Step: $i")
    }
}

// 達成左閉右開
fun useForInUntil() {
    for (i in 0 until 5) {  // 當然可以與 step 結合 (0 ~ 4)
        println("until: $i")
    }
}

// 區間 `..` & Until 都是 "升序",downTo 則是降序
fun useForInDownTo() {
    for (i in 5 downTo 0 step 2) {    // 區間 [10,0],並配合 step 使用
        println("downTo: $i")
    }
}

● 指定次數的 For 迴圈會使用 in + until


fun forControl(times : Int = 10) {
    for (i in 0 until times) {
        // TODO:
    }
}

tag 標籤 - @

● 上面的循環語句可以配合標籤一起使用;一般來說跳出迴圈必須使用 break,在 Kotlin 中也可以使用「標籤」來代替;標籤的功能就像是 C/Cgoto 一般,可以直接轉會到那一行

標籤格式: <標籤名稱>@


package class_1

fun main() {
    customFor()

    println()

    kotlinTag()
}

// 傳統 for 用法
fun customFor() {
    for(i in 0..5) {
        println("customFor i: $i")
        for (j in 0..5) {
            if (i == 2) {
                println("Till 2 use break")
                break
            }
        }
        if(i == 4) break
    }
}

/**
 * 使用標籤達到相同的效果 
 */ 
fun kotlinTag() {
// 標籤
Hi@ for(i in 0..5) {
        println("kotlinTag i: $i")

    Tag@for (j in 0..5) {
            if (i == 2) {
                println("Till 2 use Break & Tag")
                break@Tag    // 跳出 tag 標籤
            }
        }
        if(i == 4) break@Hi
    }
}

--實作結果--

Class 類就自帶標籤,標籤與類同名,範例如下


class PC {
    var CPU = "Intel-core-i5";
    var ram = 16;

    fun info2() {
        // 返回 this@PC,也就是 PC 類
        println("Cpu: ${this@PC.CPU}, ram: ${this@PC.CPU}")
    }
}

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

發表迴響