Kotlin 基礎學習+快速實踐

美團點評點餐發表於2017-07-03

作者介紹:劉高軒,美團點評Android工程師,2年Android開發經驗,現在是美團點評點餐團隊的一員。

前言

本文主要介紹了新晉Android官方開發語言Kotlin的語法基礎和實用特性,並加以簡單的快速實踐,給出了Kotlin相比Java的開發效率優勢,非常適合對Kotlin感興趣的Android開發人員進行閱讀。
本文較長(6000字左右),建議閱讀時間: 30min+

目錄

  • 1 背景
  • 2 語法速看
    • 2.1 變數型別與符號
    • 2.2 函式與方法
    • 2.3 類與繼承
    • 2.4 邏輯語句
  • 3 實用特性
    • 3.1 空指標安全
    • 3.2 擴充套件方法和屬性
    • 3.3 簡潔資料類
    • 3.4 Anko
  • 4 快速實踐
    • 4.1 配置AS
    • 4.2 Demo
  • 5 結語

背景

今年的Google I/O 2017,Kotlin正式成為Android的官方開發語言。這門被稱為“The Swift of Android”的語言(具體對比可參考Swift is like Kotlin),自Jetbrains推出至今已有六年時間,而首個官方穩定版本卻是去年2月才釋出的。也正是從去年開始,Kotlin的使用度迎來了爆炸式的增長,這裡有一張官方的GIF圖可以看出其2016年的發展速度。

Kotlin好處都有啥?誰說對了都給他。作為一個旨在取代Android開發人員基數眾多的Java語言的新興語言,完全與Java老大哥割裂開,那日後的推廣肯定是步履維艱。Kotlin巧妙地作為一個靜態JVM語言誕生,與Java完全相容,又比Java要更加簡潔,同時也處理了讓無數開發者頭疼的NullPointerException問題,顯得很有吸引力。對於一個有經驗的Android開發者來說,學習Kotlin的曲線相當平緩,可以幾乎零成本去改造已有Android專案的部分程式碼。面對這充滿了新特性的語言,誰會不動心呢?

Kotlin語言主要有以下幾個特點:

  • 高度相容Java:Kotlin也可以呼叫傳統Java語言的各種類庫。由於最終都是編譯為JVM位元組碼執行,Kotlin可以與Java存在於同一個專案中,互相呼叫。開發者可以部分改造專案中的程式碼,嘗試其新語言特性。官方提供Java程式碼到Kotlin程式碼的轉換工具。開發者可以把現有的Java/Android專案一鍵轉換為Kotlin專案,實現零成本的改造。
  • 程式碼簡潔高效:語法精煉,無處不在的型別推斷,自動生成通用方法,支援Lamda表示式,使Kotlin的程式碼行數遠低於傳統Java程式碼。而程式碼量的壓縮,客觀上會提高開發效率。
  • 空指標安全:通過符號“?”定義物件的nullable,讓開發者不用為了避免NPE而寫太多防禦性程式碼。
  • 函數語言程式設計:支援讓函式作為引數或者返回的高階函式用法,支援流式API,支援擴充套件方法。

2 語法速看

2.1 變數、型別與符號

基礎型別

java中存在int,float,boolean等基礎型別,這些基礎型別在Kotlin裡將全部以物件的形式繼續存在。隨之而來使用上也發生一些變化,有幾點需要注意下:

// Int無法自動轉換為Double, 需要自己先做型別轉換(as Double, toDouble(), 方式很多)
var a: Int = 2
var b: Double = a.toDouble()
// Char不能直接等值於其對應的ASCII碼值,需要型別轉換
var c: Char = 'a'
var ca: Int = c.toInt()複製程式碼

變數宣告

Kotlin中使用var定義變數(和js很像),使用val定義常量(相當於java當中的final)。定義變數時既可以指定型別,也可以不指定,Kotlin支援型別推斷。

var name = "me" // 型別為String
var name: String = "me" // 型別為String
val TAG: String = "KotClassA"複製程式碼

需要注意的是,你不能直接寫一個var num丟在程式碼裡不初始化值,編譯器會無法推斷它的型別

var name // 編譯器報錯
var name: String // 型別為String複製程式碼

行尾標識

與Java中以“;”符號區分每行的結尾不同,Kotlin中不再需要在每行程式碼的結束位置寫“;”。當然如果你一時改不了寫Java時的習慣,IDE也並不會報錯,只會友好地把“;”置灰並下劃線,提示你這是多餘之舉。

型別宣告

Java語言中,“:”符號主要出現於三元運算子“A ? B : C”中,for迴圈時遍歷列表項和switch的每種情形分支。而在Kotlin語言中,“:”被廣泛用於變數型別的定義。

// 定義變數型別
fun common() {
    var ka: KClassA
    var kb: KClassB
}
// 定義函式的引數和返回值
fun helloStr(str: String): String {
    var strHello: String = "hello"
    strHello += str
    return strHello
}複製程式碼

“:”還被用於宣告類繼承或介面實現。

interface KInterfaceA {
    ...
}
open class KClassA(n: Int): KInterfaceA {
    ...
}
class KClassB(n: Int): KClassA(n) {
    ...
}複製程式碼

此外,如果你想在Kotlin程式碼中使用Java類,也需要用到“:”符號。連續兩個“:”表明對Java類的呼叫。

val intent = Intent(this, MainActivity::class.java)複製程式碼

型別檢測

Java語言中使用instanceof來判斷某變數是否為某型別,而Kotlin中使用更短小更直觀的is來進行型別檢測。

if (num instanceof Double) { ... }  // Java程式碼
if (num is Double) { ... }  // Kotlin程式碼複製程式碼

字串模板

Java中使用字串模板會比較麻煩,而且不太直觀。而Kotlin裡使用則異常便捷好用。

// Java中字串模板兩種常用形式
String name = "我";
int age = 25;
String.format("%s今年%d歲", name, age);
MessageFormat.format("{0}今年{1}歲", name, age);
// Kotlin中更直觀的字串模板形式
var name = "我"
var age = 25
"${name}今年${age}歲"複製程式碼

2.2 函式與方法

Kotlin中的函式通過關鍵字fun定義的,具體的引數和返回值定義結構如下。

fun test(para1: Int, para2: String): String { ... }複製程式碼

Kotlin中的函式可以是全域性函式,成員函式或者區域性函式,甚至還可以作為某個物件的擴充套件函式臨時新增,這個作為Kotlin的一大實用特性,下文會有具體講解。
Kotlin函式引數還有預設值和可變引數的特性,分別來看一下:
對Kotlin函式中的某個引數可以用“=”號指定其預設值,呼叫函式方法時可不不傳這個引數,但其他引數需要用“=”號指定。下文例子中沒有傳遞引數para2,其實際值為預設值"para2"

fun test(para1: Int, para2: String = "para2", para3: String): String { ... }
test(22, para3 = "hello")複製程式碼

可變引數值的話,需要用關鍵字vararg來定義。這裡需要注意的是,一個函式僅能有一個可變引數。該可變引數不一定得是最後一個引數,但當這種情況下時,呼叫該方法,需要給其他未指明具體值的引數傳值。

fun test(vararg para1: String, para2: String): String { ... }
test("para1", "para4", "para5", para2 = "hello")複製程式碼

2.3 類與繼承

Kotlin中也使用class關鍵字定義類,所有類都繼承於Any類,類似於Java中Object類的概念。類例項化的形式也與Java一樣,但是去掉了new關鍵字。

建構函式

類的建構函式分為primary constructor和secondary constructor,前者只能有一個,而後者可以有多個。如果兩者都未指定,則預設為無引數的primary constructor。
primary constructor是屬於類頭的一部分,用constructor關鍵字定義,無可見性欄位定義時可省略。初始化程式碼需要單獨寫在init程式碼塊中,方法引數只能在init程式碼塊和變數初始化時使用。
secondary constructor也是用constructor關鍵字定義,必須要直接或間接代理primary constructor。

class Student(name: String) { // primary constructor
    var mName: String = name
    init {
        println("Student is called " + name)
    }

    constructor(age: Int, name: String):this(name) {
        println("Student is ${age} years old")
    }
}複製程式碼

繼承

類繼承使用符號“:”表示,介面實現也一樣,不做原本Java中的extends和implement關鍵字區分。Kotlin有一點與Java大為不同,即Java中類預設可被繼承,只有被final關鍵字修飾的類才不能被繼承。而Kotlin中直接取消了final關鍵字,所有類均預設不可被繼承。神馬?這還怎麼物件導向程式設計?先別急,Kotlin中新增了open關鍵字,僅有被open修飾的類才可以被繼承。

單例與伴隨物件

日常開發中寫一個單例類是很常見的行為,Kotlin中直接將這種設計模式提升到語言級別,使用關鍵詞object定義單例類。這裡需要注意,是全小寫。Kotlin中區分大小寫,Java中原本指所有類的父類Object已棄用。單例類訪問直接使用類名,無建構函式。

object Shop(name: String) {
    fun buySomething() {
        println("Bought it")
    }
}
Shop.buysomething()複製程式碼

Java中使用static標識一個類裡的靜態屬性或方法,可以被這個類的所以實現使用。Kotlin改為使用伴隨物件,用companion修飾單例類object,來實現靜態屬性或方法功能。

class Mall(name: String) {
    companion object Shop {
        val SHOP_NAME: String = "McDonald" // 等同於Java中寫public static String
        fun buySomething() { // 等同於Java中寫public static void
            println("Bought it")
        }
    }
}
Mall.buySomething()複製程式碼

2.4 邏輯語句

if-else語句

Kotlin中的if-else語句與Java一致,結構上都是if (條件A) { 條件A為真要執行的操作 } else { 條件A為假要執行的操作 }
這裡主要要介紹的是Kotlin的一個特點,即if-else語句可以作為一個邏輯表示式使用。不僅如此,邏輯表示式還可以以程式碼塊的形式出現,程式碼塊最後的表示式作為該塊的值。

// 邏輯表示式的使用
fun maxNum(x: Int, y: Int): Int {
    var max = if (x > y) x else y
    return max
}
// 程式碼塊形式的邏輯表示式
fun maxNumPlus(x: Int, y: Int): Int {
    var max = if (x > y) {
        println("Max number is x")
        x
    } else {
        println("Max number is y")
        y
    }
    return max
}複製程式碼

when語句

Kotlin中的when語句取代了Java中的switch-case語句,功能上要強大許多,可以有多種形式的條件表達。與if-else一樣,Kotlin中的when也可以作為邏輯表示式使用。

// 邏輯表示式的使用
fun judge(obj: Any) {
    when (obj) {
        1 -> println("是數字1")
        -1, 0 -> println("是數字0或-1")
        in 1..10 -> println("是不大於10的正整數")
        "abc" -> println("是字串abc")
        is Double -> println("型別是雙精度浮點數")
        else -> println("其他操作")
    }
}複製程式碼

標籤

Kotlin中可以對任意表示式進行標籤標記,形式為abc@,xyz@。而這些標籤,可以搭配return、break、continue等跳轉行為來使用。

fun labelTest() {
    la@ for (i in 1..10) {
        println("outer index " + i)
        for (j in 1..10) {
            println("inner index " + j )
            if ( inner % 2 == 0) {
                break@la
            }
        }
    }
}複製程式碼

其他

for語句、while語句、continue語句和break語句等邏輯都與Java基本一致,這裡不再贅述。

3 實用特性

3.1 空指標安全

在寫Java程式碼時,最常出現線上上的crash問題大概就是NullPointerException了。技術上來說這樣的問題修復起來很快,沒什麼難度,但往往由於日常開發中沒有寫足夠多的防禦性程式碼,導致此類問題一直困擾著我們。Java作為一個古老的語言並沒有空指標安全功能,這使得當物件層級套用的時候,想要獲取最裡面的某個屬性,需要從外到內依次做一遍非空判斷來避免NPE。相似的場景太多,導致這在程式碼成本上是很大的。

Kotlin中,當我們定義一個變數時,其預設就是非空型別。如果你直接嘗試給他賦值為null,編譯器會直接報錯。Kotlin中將符號“?”定義為安全呼叫操作符。變數型別後面跟?號定義,表明這是一個可空型別。同樣的,在呼叫子屬性和方法時,也可以用字元?進行安全呼叫。Kotlin的編譯器會在寫程式碼時就檢查非空情況,因此下文例子中,當s2有前置條件判斷為非空後,即便其本身是可空型別,也可以安全呼叫子屬性或方法。對於ifelse結構的邏輯,Kotlin還提供了“?:”操作符,極大了簡化了程式碼量又不失可讀性。Kotlin還提供“!!”雙感嘆號操作符來強制呼叫物件的屬性和方法,無視其是否非空。這是一個挺危險的操作符,除非有特殊需求,否則為了遠離NPE,還是少用為妙。

var s1: String = "abc"
s1 = null // 這裡編譯器會報錯
var s2: String? = "abc"
s2 = null // 編譯器不會報錯

var l1 = s1.length // 可正常編譯
var l2 = s2.length // 沒有做非空判斷,編譯器檢查報錯

if (s2 != null) s2.length // Java式的判空方案
s2?.length // Kotlin的安全呼叫操作符?。當s2為null時,s2?.length也為null
if (s2 != null) s2.length else -1 // Java式判空的ifelse邏輯
s2?.length ?: -1 // Kotlin的elvis操作符
s2!!.length // 可能會導致NPE複製程式碼

3.2 擴充套件方法和屬性

相信作為一個Java/Android開發者,大家都寫過很多Base類,繼承原生父類的同時,封裝一些通用方法,供子類使用。亦或是把這類通用方法,專門放置到一個XXUtils類裡,作為工具類出現。這樣做是為了程式碼結構的清晰,但也是一種無奈。由於無法修改原生類的內容,我們只能藉助繼承或者以面向方法的思維來寫工具類。這點在Kotlin裡得到了完美解決。Kotlin支援在包範圍內對已存在的類進行方法和屬性擴充套件。

我們以Android最常用的showToast方法舉個擴充套件方法的例子,以lastIndex屬性舉個擴充套件屬性的例子,如下。在這樣強大的特性下,寫程式碼都成了一種享受。

// 擴充套件方法
fun Context.showLongToast(msg: String) {
    Toast.makeText(this, msg, Toast.LENGTH_LONG).show()
}
// 擴充套件屬性
val <T> ArrayList<T>.lastIndex: Int get() = size -1

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        showLongToast("hello") // 給Context類擴充套件了showToast方法,可以在任何有context的地方直接呼叫了

        var mList = ArrayList<String>()
        mList.lastIndex // 任何ArrayList均可以呼叫該屬性
        ...
    }
    ...
}複製程式碼

這裡需要注意兩點:1.擴充套件需要在包級範圍內進行,如果寫在class內是無效的。2.已經存在的方法或屬性,是無法被擴充套件的,依舊會呼叫已有的方法。

3.3 簡潔資料類

相信大家都寫過資料類,或者自動化生成的資料model,通常都是由多個屬性和對應的getter、setter組成。當有大量多屬性的資料類時,不僅這些類會因為大量的getter和setter方法而行數爆炸,也使整個工程方法數驟增。Kotlin中也做了這層特性優化,提供了資料類的簡單實現。不用再寫get和set方法,這些都由編譯器背後去做,你得到的是一個清爽乾淨的資料類。具體使用參考下面的例子。

data class Student (
    var name: String,
    var age: Int,
    var hobby: String?,
    var university: String = "NJU"
)
fun printInfo() {
    var s: Student = Student("Ricky", 25, "playing Gwent")
    println("${s.name} is from ${s.university}, ${s.age} years old, and likes ${s.hobby}")
}複製程式碼

3.4 Anko

Anko是Jetbrains官方提供的一個讓Kotlin開發更快速簡單的類庫,旨在使程式碼書寫更加清晰易懂,形式上為DSL程式設計。

No findViewById

Android開發過程一定都寫過大量的findViewById。這本身就是個消耗資源的方法,編碼時還極為不便,需要強制轉換為具體的View型別才能呼叫其方法。通過引入支援註解的庫,可以使這個過程略微簡單化一些。

// 傳統Android中的View內容初始化
TextView tvName = (TextView) this.findViewById(R.id.tv_name);
tvName.setText("Ricky");
// 註解方式
@BindView(R.id.tv_name)
TextView tvName;
tvName.setText("Ricky");複製程式碼

這樣還是顯得不夠簡潔,而Kotlin給出了一種最為簡便的方式。

import kotlinx.android.synthetic.main.activity_main.* // activity_main為具體的佈局xml檔名
...
tvName.text = "Ricky";複製程式碼

你只需要在具體的頁面中按照上面的格式import下,就可以在整個頁面裡很方便的使用xml裡的view操作了。不需要型別轉換,不需要新建變數,不需要findViewById,孰優孰劣,相信大家心中都有了答案。

Simple startActivity

通常,在Android裡,當我想開啟一個新頁面,並給它傳遞一些引數時,我需要按照如下的方式編碼。

Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.putExtra("userid", 10001);
intent.putExtra("username", "ricky");
startActivity(intent);複製程式碼

而強大的Anko給我們提供了一種極為方便的寫法。無論是無參還是有參,還是需要RequestCode,都非常簡潔易懂,是不是一看就特別心動?

startActivity<MainActivity>()
startActivity<MainActivity>("userid" to 10001, "username" to "ricky")
startActivityForResult<MainActivity>(101, "userid" to 10001, "username" to "ricky")複製程式碼

DSL Layout

上面說到不再使用findViewById,還是基於使用xml來編寫Android頁面這個基礎。倘若你想徹底革新寫法,換一種更直觀的DSL方式來寫Android頁面呢?Anko就提供了這樣的方案。相比之下,除了可讀性增加之外,也節約瞭解析xml檔案消耗的資源。

inner class LoginAnkoUI : AnkoComponent<LoginActivity> {
    override fun createView(loginAnkoUI: AnkoContext<LoginActivity>): View {
        return with(loginAnkoUI) {
            verticalLayout {
                val textView = textView("使用者名稱") {
                    textSize = sp(15).toFloat()
                    textColor = context.resources.getColor(R.color.black)
                }.lparams {
                    margin = dip(10)
                    height = dip(40)
                    width username= matchParent
                }
                val username = editText("輸入...")
                button("登入") {
                    onClick { view ->
                        toast("Hello, ${username.text}!")
                    }
                }
            }
        }
    }
}複製程式碼

只要最後在Activity里加一句呼叫,便可以使用Anko寫的頁面了。是不是看上去更直觀了呢?

LoginAnkoView().setContentView(this@LoginActivity)複製程式碼

4 快速實踐

4.1 配置Android Studio

作為官方開發語言,在Android Studio 3.0版本中,已經內嵌了對Kotlin的支援。和筆者一樣還在使用2.x版本開發的小夥伴們,也不用擔心需要花時間升級AS才能體驗到Kotlin。JetBrains提供了完善的外掛支援,直接開啟Preferences去配置外掛,找到Kotlin下載安裝下就好啦。

Kotlin 基礎學習+快速實踐 Kotlin 基礎學習+快速實踐 Kotlin 基礎學習+快速實踐

外掛安裝完畢,還需要build.gradle裡新增下依賴。
Kotlin 基礎學習+快速實踐 Kotlin 基礎學習+快速實踐

如果你不清楚當前最新的kotlin版本是什麼的話,這裡也有一個更簡便的方法來給專案新增kotlin依賴。
首先你的專案中要有一份java程式碼,然後在外掛安裝正常的情況下,你可以在Code選單看到一鍵把Java程式碼轉換為Kotlin的功能。

Kotlin 基礎學習+快速實踐 Kotlin 基礎學習+快速實踐

轉換完畢後,當你嘗試修改這個.kt程式碼檔案時,Android Studio便會提醒你Kotlin尚未配置。

Kotlin 基礎學習+快速實踐

這個自動化配置過程,可以看到目前外掛支援到的最新的Kotlin版本。換言之外掛及時最新的話,你這裡就可以選擇到最新的Kotlin版本。這裡也可以選擇只將某個模組配置為支援Kotlin,或者全域性支援。

Kotlin 基礎學習+快速實踐

配置完畢後,我們可以看到build.gradle檔案裡已經自動新增了依賴程式碼,Sync一下就ok了。

Kotlin 基礎學習+快速實踐

由於要充分發揮Kotlin的特性,將Anko的相關程式碼依賴也引入進來

Kotlin 基礎學習+快速實踐

4.2 Demo

下面會給大家展示一個小Demo的核心程式碼,完整程式碼可以檢視KotlinDemo。Demo將分別用Java寫法和Kotlin寫法編寫同樣的頁面,以此對比出優劣。

Demo包含一個Java實現的公共首頁,首頁中有兩個按鈕入口,分別跳轉到用Java編寫的列表頁和用Kotlin編寫的列表頁。各自的列表頁都會實現一個Item點選跳轉到詳情頁的功能,並在詳情頁顯示具體資訊。

Java實現效果:Kotlin 基礎學習+快速實踐Kotlin實現效果:Kotlin 基礎學習+快速實踐

列表頁程式碼

// Java實現
public class JListActivity extends AppCompatActivity implements View.OnClickListener, AdapterView.OnItemClickListener {

    // View
    private ListView listView;
    private Button btnClearData;
    private Button btnUpdateData;

    // Data
    private ArrayList<JStudent> studentList = new ArrayList<>();
    private JListAdapter listAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_java);
        initView();
        initData();
    }

    private void initData() {
        listAdapter = new JListAdapter(studentList);
        listView.setAdapter(listAdapter);
    }

    private void initView() {
        listView = (ListView) findViewById(R.id.java_list_view);
        btnClearData = (Button) findViewById(R.id.java_clear_btn);
        btnUpdateData = (Button) findViewById(R.id.java_update_btn);

        listView.setDividerHeight(0);

        listView.setOnItemClickListener(this);
        btnClearData.setOnClickListener(this);
        btnUpdateData.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        if (view == btnClearData) {
            studentList.clear();
            listAdapter.notifyDataSetChanged();
            showShortToast("已清空");
        } else if (view == btnUpdateData) {
            studentList.addAll(FakeServer.randomJavaResponse());
            listAdapter.notifyDataSetChanged();
            showShortToast("已更新10條資料");
        }
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
        Intent intent = new Intent(JListActivity.this, JInfoActivity.class);
        intent.putExtra("stu_name", studentList.get(i).getName());
        intent.putExtra("stu_age", studentList.get(i).getAge());
        intent.putExtra("stu_hobby", studentList.get(i).getHobby());
        intent.putExtra("stu_university", studentList.get(i).getUniversity());
        startActivity(intent);
    }

    private void showShortToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }
}複製程式碼
// Kotlin實現
class KListActivity : AppCompatActivity() {

    var studentList: ArrayList<KStudent> = ArrayList()
    var listAdapter: KListAdapter = KListAdapter(studentList)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ListUI().setContentView(this@KListActivity)
    }

    fun clearList() {
        studentList.clear()
        listAdapter.notifyDataSetChanged()
        showShortToast("已清空")
    }

    fun updateList() {
        studentList.addAll(FakeServer.randomKotlinResponse())
        listAdapter.notifyDataSetChanged()
        showShortToast("已更新10條資料")
    }

    fun gotoItemInfo(position: Int) {
        var student = studentList[position]
        startActivity<KInfoActivity>("stu_name" to student.name, "stu_age" to student.age, "stu_hobby" to student.hobby, "stu_university" to student.university)
    }

}複製程式碼

資料類程式碼

// Java實現
public class JStudent {

    private int id;
    private String name;
    private int age;
    private String hobby;
    private String university;

    public JStudent(int id, String name, int age, String hobby, String university) {
        setId(id);
        setName(name);
        setAge(age);
        setHobby(hobby);
        setUniversity(university);
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getHobby() {
        return hobby;
    }

    public String getUniversity() {
        return university;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public void setUniversity(String university) {
        this.university = university;
    }

}複製程式碼
// Kotlin實現
data class KStudent(var id: Int, var name: String, var age: Int, var hobby: String, var university: String)複製程式碼

上面的程式碼對比已經能看出一些驚人的差距,我們再統計一下用兩種方式編寫的具體程式碼行數,以評判兩者的開發效率。

Java Part/LOC Kotlin Part/LOC
ListActivity 85 38
ListUI 52 62
InfoActivity 62 29
InfoUI 114 120
ListAdapter 71 33
ListItemUI 48 67
Student Data Class 64 1
Total 496 350

可以看到,使用了Anko編寫的Kotlin頁面UI,在程式碼行數上甚至比xml編寫還要多一點。但是由於不再需要findViewById,對應Activity中減少了很多邏輯,程式碼行也少了很多。同時,這種寫法也節約了CPU去解析xml生成頁面的資源和時間。
最終此Demo中使用Java和Kotlin編寫相同的頁面功能,Kotlin比Java少了30%的程式碼開發量。再加上空指標安全等特性,表現可以說是非常亮眼。

5 結語

Kotlin作為一個JVM上的新語言,充分相容了老大哥Java的諸多功能,又構建了很多自身優秀特性,提供了大量便捷易懂、結構清晰的開發形式。筆者作為一個Android開發,非常樂於在今後的開發中嘗試完全化的Kotlin專案。本文限於篇幅,僅能展現出其諸多特點的一點皮毛,更多新特性還需要各位看官自己在實際使用中挖掘。

套用劉禹錫的一句詩來結束本文吧。“芳林新葉催陳葉,流水前波讓後波”,期待吸收了Java之長的Kotlin,能在未來有更好的表現。

參考文章

  1. Kotlin Official Docs
  2. Why Kotlin is my next programming language
  3. 為什麼我要改用Kotlin
  4. 寫給Android開發者的Kotlin入門
  5. NullPointException利器Kotlin可選型

相關文章