转载

Kotlin 實戰範例 (1) 為什麼要學 Kotlin

Kotlin 實戰範例 (1) 為什麼要學 Kotlin

Kotlin 實戰範例

Java 寫的好好的,為什麼要改用 Kotlin 呢?Kotlin 提供了哪些 Java 沒有的語言特性?這些特性如何讓我們寫程式更順手、更開心呢?

還是要先聲明,每個程式語言的誕生都是想要解決特定的問題,好壞與否其實關乎個人的選擇,這裡提及其他的 JVM 語言僅用來互相比較。

JVM 語言眾多,Kotlin 只是其中一種,藉由和其他 JVM 語言的比較可以瞭解 Kotlin 在設計上的哲學。Kotlin 做為一個新生代的程式語言,可以從許多程式語言上學到優秀的解決方法,讓語法更加靈活與現代化。

1.1 眾多的 JVM 語言

程式碼必須被編譯為機器語言讓電腦執行,針對不同的作業系統及硬體裝置都必須特別處理,因此當年為了解決這個問題而打造了 JVM (Java Virtual Machine, Java 虛擬機器),由它來處理不同作業系統及硬體裝置的部分,我們寫的程式只要編譯成位元碼 (byte code) 交由 JVM 來處理即可。

由於這個設計,只要其他程式語言可以編譯成 JVM 能讀取的位元碼,就能夠利用 JVM 來達到跨平台的能力,於是就產生了許多可以在 JVM 上運行的程式語言,可以看看 JVM 語言清單 。

在 Kotlin 之前比較熱門的 JVM 語言有 Scala 及 Groovy。Kotlin 受這兩種語言的啟發而被設計出來,細看這三種語言的語法,會有許多相似之處。 Groovy 在 2003 年發表,是個同時包含動、靜態型別系統的語言,受到 Java 、Python 及 Ruby 等語言的啟發,Groovy 就像是 JVM 版的 Python。Scala 也差不多在同一個時期出現,受啟發的語言眾多,語法中可以看到這些語言的影子。

Kotlin 接收了這些語言的設計哲學,並且將目標放在接近 Java 的編譯速度、檔案大小及方法數量上,這也許就是 Kotlin 被選為 Android 官方語言的原因之一,因為 Android 有方法數量上限的 64k 的限制 (現在可以透過 Multidex 來解決),如果使用 Scala 或 Groovy ,方法數量會爆增,很容易就超過這個限制,可以看看 SidneyXu/AndroidDemoIn4Languages 的實驗 (註:這個實驗是 2017 年做的,數據可能過時,請參考就好),該實驗以 4 種 JVM 語言 Java、Groovy、Scala、Kotlin 來做比較,請特別注意檔案大小及方法數量,除了 Kotlin 較接近 Java 以外,其他兩個都大上許多。

1.2 Kotlin 的優點

Kotlin 和 Java 的互相操作性做的很好,也就是說,我們可以在現有專案中漸進地使用 Kotlin,不必一次將原本的 Java 專案全部轉移成 Kotlin。要在 Java 中呼叫 Kotlin 的程式碼,或是反過來都沒問題,這樣的好處是,我們可以在 Kotlin 中使用所有已經存在的 Java 框架和類別庫,這對剛起步的 Kotlin 來說幫助非常大。

Kotlin 和 Java 在語法上雖然有不少差異,但是主要還是在思考方式的不同,Kotlin 在設計上積極地使程式碼變得簡潔,並且讓語意清楚,對於已經在使用 Java 的讀者,建議在寫 Kotlin 時暫時忘掉 Java ,當成初學者來學習,避免寫出很像 Java 的 Kotlin 程式碼。

在寫 Java 的時候,因為沒有明確的方法可以知道某個物件是否為空 (null),如果不小心使用到這個物件,就會引發空指標的例外錯誤 (NPE, NullPointerException) ,因此,在 Java 8 時加入了 Optional 的解決方案,不過這個功能在使用上並不是那麼優雅。Kotlin 在設計之初就考慮到這個問題,內建了 null 安全機制,在宣告變數時就必須指定該變數是否接受 null ,這樣在編譯階段就能提早發現並且優雅的處理。

Kotlin 是個混合型的程式語言,同時擁有物件導向及函數式程式設計的特性,它的函式是頭等函式 (first-class function),也就是說,一個函式可以被當成另外一個函式的參數傳入或回傳值傳出 (如果你會 Javascript 就能明白),而且函式不一定要寫在類別裡面,它可以單獨存在,再加上擴充函式這個非常棒的特性,在撰寫程式時可以非常靈活,以上這些特性在 Java 中是沒有的。

最後,如我們前面提過的,Kotlin 的編譯結果很接近 Java,並且已經被 Android 團隊列為官方的第一優先 (Kotlin-first) 開發語言,如果想開發 Android 應用程式,這已經是不用多想的必學程式語言;在其他領域如網頁框架及原生應用程式等等,這些更多更廣的應用都非常令人期待。

1.3 看看 Kotlin 如何做

1.3.1 程式的起點

Java 必須先建立一個類別,並在其中建立一個靜態方法 main() 做為程式的起點,請看範例:

/* Java */
public class Hello {
  public static void main(String[] args) {
    System.out.print("Hello Java");
  }
}

Kotlin 不需要特別建立類別,它的函式是頭等函式,等級和類別一樣,因此可以直接以 main() 函式做為程式的起點,請看範例:

/* Kotlin */
fun main(args: Array<String>) {
  print("Hello Kotlin")
}

1.3.2 結尾的分號

Java 必須在敍述行的結尾加上分別,Kotlin 則不需要,除非將兩行敍述寫成一行,中間才需要加上分號,但是不建議這麼做。

1.3.3 資料類別

詳細的內容會有專門的章節做介紹,這裡直接看範例:

/* Java */
public class Book {
    private String isbn;
    private String title;
    private String description;
    private int price;

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}

相同的內容在 Kotlin 中只要一行,為了容易閱讀,將程式碼斷行排列,請看範例:

/* Kotlin */
data class Book(
  var isbn:String, 
  var title:String, 
  var description:String, 
  var price:Int
)

註: Java 14 預計會引進 Records ,其特性和 data class 很像。

1.3.4 安全的 null

使用未初始化的空物件會導致程式發生 NPE (NullPointerException) 的例外錯誤,於是我們會在程式碼中不斷地到處檢查物件是否為 null。

Java 8 新增了一個 Optional 的新功能來避免 NPE,而 Kotlin 則內建在資料型別中,以問號 ? 來表示可能為空值的情況,請看範例:

/* Java */
import java.util.Optional;

public class App {

  public static void main(String[] args) {
    String name = null;
    print(name);
    // 使用 Java 8 的 Optional
    Optional<String> optName = Optional.ofNullable(name);
    print(optName);
  }

  private static void print(String name) {
    // 傳統寫法
    if (name != null) {
      System.out.println(name);
    }
  }
  
  private static void print(Optional<String> optName) {
    // 和傳統寫法差不多,只是換成呼叫方法
    if (optName.isPresent()) {
      // 必須呼叫 get() 方法取值
      System.out.println(optName.get());
    }
    // 用這個可以少寫 if
    optName.ifPresent( name -> System.out.println(name));
    // 或是在發生 null 時給其他的值
    System.out.println(optName.orElse("is null"));
  }
}

註:若要瞭解 Java 8 Optional 的完整用法,可以參考: Java8 新功能筆記 (4) - Optional 。

在 Optional 之前,由於方法中無法得知傳進來的引數值是不是 null,一般來說都會防衛式的去檢查;在使用 Optional 後,我們可以明確得知傳入的引數值可能 null,因此做出額外的檢查及處理。現在來看看 Kotlin 怎麼做:

/* Kotlin */
fun main(args: Array<String>) {
  // 這樣會編譯錯誤
  // var name: String = null
  
  var name: String? = null
  
  // 編譯錯誤,這個函式不接受可能 null 的變數傳入
  // printName(name)
  
  var name2: String = "Tony"
  printName(name2)
}

fun printName(name: String) {
  println(name)
}

Kotlin 在設計型別時就加上 null 判斷的機制,因此不需要在程式碼上做額外的操作,不僅簡潔也更明確,而且這些全都在編譯時期就能檢查出來。

1.4 Kotlin 快問快答

:speech_balloon: Kotlin 是開源且免費的嗎?

是。使用 Apache 2.0 license 授權,原始碼在 GitHub 。

:speech_balloon: Kotlin 是屬於物件導向還是函數式程式語言?

同時擁有兩者特性,可以同時混用物件導向及函數式的語法。

:speech_balloon: 使用 Kotlin 勝過 Java 的優點是什麼?

簡潔。Kotlin 官方粗估,相同功能的程式碼行數約可較 Java 減少 40%。型別系統內建非 null 型別的支援,大大增加型別安全及減少 NPE 的發生。還有其他從函數式程式語言學習而來的功能。

:speech_balloon: Kotlin 是否相容 Java?

是的。Kotlin 和 Java 程式碼可以完全互相操作,無縫地在 Kotlin 中呼叫 Java 程式碼,或反過來。

:speech_balloon: 哪些類型應用可以使用 Kotlin ?

除了 Android 以外,包含網站伺服端 (Server)、前端 (Javascript) 、桌面應用 (JavaFx) 及正在開發的原生應用 (Kotlin/Native) 還有資料科學等等。

1.5 總結

Kotlin 的許多語言特性都不是原創,而是借鏡其他語言的優點,並且設計的更好用。程式碼簡潔、語意清 、容易閱讀,就能減少犯錯的機會,對比 Java 來說可以提高不少生產力,Kotlin 是值得一學的程式語言。

下篇預告:Kotlin 實戰範例 (2) 基礎 (變數、型別)

完整內容可以參考電子書: Google Play Pubu

原文  http://blog.tonycube.com/2020/07/kotlin-by-example-1-why-kotlin.html
正文到此结束
Loading...