Kotlin, Android的Swift


Kotlin, Android的Swift

蘋果已經用Swift代替Objective-C,一種古老的語言,來進行iOS的開發了。明顯Android開發也有這個趨勢。

雖然現在已經可以選擇Scala或者Groovy等基於JVM的語言開發Android應用來嘗嘗鮮,但是弊端卻顯而易見。
要引入一個全新的開發語言,那么就意味着需要引入這個語言的全部的運行時。這簡直就是噩夢。因為這會給
極大的增加應用包的大小,還不說65535方法問題。小的應用還可以,但是這不是一個合適的替代語言應該有的問題。

Kotlin

介紹一下Kotlin--一個基於JVM的語言。由JetBrains(他們開發了IntelliJ IDEA的一個系列和Android Studio)
開發,並由聖彼得堡附近的一個小島命名,負責這個項目的開發團隊就在這個小島辦公。在2011年為外界
所致,並在幾年后的第二個里程碑(M2)發布了對Android的支持(翻譯的時候已經發布了1.0正式版)。

特性

這個新的語言有什么特色呢,你可能會問。有很多!不過本文會集中講述Java應該有而一直沒有的上面。

命名和可選參數

命名參數是一個很簡單的語言特性,但是卻讓代碼更加易讀,尤其是那些有很多參數的函數簽名。

看下面的例子:

void circle(int x, int y, int rad, int stroke) {
    ...
}

在java調用的時候看起來是這個樣子的:

circle(15, 40, 20, 1);

要多次查看函數簽名才能知道每個參數的具體作用。在Kotlin里,定義是這樣的:

fun circle(x: Int, y: Int, rad: Int, stroke: Int) {
    ...
}

調用就更好了:

circle(15, 40, rad = 20, stroke = 1)

假設我們現在需要把stroke參數設定為可選的,在Java里你只能overload出另一個方法,這個方法
少一個參數,然后在里面調用第一個方法:

public void circle(int x, int y, int rad, int stroke) {
    ...
}

public void circle(int x, int y, int rad) {
    circle(x, y, rad, 1);
}

但是在Kotlin里,一切變得簡單:

fun circle(x: Int, y: Int, rad: Int, stroke: Int = 1) {
    ...
}

不是什么大的功能改進,但是Java始終沒有。

Lambda表達式

最近函數式編程日漸流行。Kotlin也支持lambda表達式。

我們先來看一個簡單的。假設你有一個整數列,而且要刪除全部的奇數。

val numbers = listOf(1, 2, 3, 4, 5)

println(numbers.filter { it % 2 != 0 })
// 輸出:[1, 3, 5]

這個函數把list的元素類型為輸入參數類型,這里是integer。並輸出一個boolean型的結果。如果我們把
filter的lambda表達式轉化為一個明顯的變量寫出來的就更容易理解了:

val predicate: (Int) -> Boolean = { it -> it % 2 != 0 }
numbers.filter(predicate)

這一語法和其他的而支持lambda表達式的語言的語法相差不大,所以不多做解釋。

Null和類型安全

總是要檢查變量是否為null也是Java里一個很煩人的事。這個問題在Kotlin里被部分解決。

如果你用傳統的方法定義一個變量,那么編譯器是不允許其值為null的。

var text1: String = "something" // 木有問題
var text2: String = null // 無法編譯

那么定義的變量的值需要為null怎么辦呢?你要專門定義一個值可為null的變量。值可為null的變量,用變量
類型后面的問號來明確指定。

var text2: String? = null // 木有問題

調用的時候也需要問號。

text2?.replace(" ", "-")

這句的意思是:如果text2為空,那么replace()方法會被忽略並且不會有NullPointerException異常拋出。

如果你接手了一個可選類型(optional type)的變量,你可以百分之百的確認變量的值不會為null(這在Adnroid的API里
非常多見,雖然方法定義返回值為空可空類型,但是從來不會返回null),然后可以強制作為非空調用方法。

text2!!.replace(" ", "-")

這個時候,如果text2為null的話就會拋出NulPointerException異常。所以小心使用。

類型安全的另一個意義是類型檢測。假設你又一個Context的實例並且需要檢測這個實例是否為Activity類型,然后調用
一些activity才有的方法。

val context = getContext()
if (context is Activity) {
    context.finish()
}

類型檢測之后你就可以把context作為一個activity類型的實例來使用了,不需要強制類型轉換。和Java的
instanceOf方法一樣,is也是null安全的。即使getContext()返回一個null,上面的代碼也
不會崩潰。

數據對象(Data object)

在寫數據對象的時候,很多你需要手動實現的,比如:toString(), 'hashCode()以及equals()`。即使
現在很多的IDE已經減輕了一部分工作量,但是添加了新的成員后再更新這些實現也是非常的麻煩。

Kotlin里不用再為這些操心了。你需要做的只是在類定義的前面加一個data的修飾,上面的方法就已經隱式的生成了。

data class Island(val name: String? = null)

如果你初始化上面的類,會自動生成一個人類可以讀懂的toString()方法。

val island = Island("Kotlin")
println(island.toString())  // 輸出:Island(name=Kotlin)

同理,如果我們用同一個名字創建另外一個實例,這個實例會equal之前創建的實例。並且他們的hashCode()值也一樣。

val island = Island("Kotlin")
val island2 = Island("Kotlin")

assert(island.equals(island2))
assert(island.hashCode() == island2.hashCode())

如果你要定制以上的方法,那么,當然,你還是要手寫的。

單例

單例是一個非常常用的方法。Kotlin省去了創建單例的時候需要的靜態getInstance()方法和私有的構造函數。
Kotlin使用object聲明。

object ApiConfig {
    val baseUrl: String = "https://github.com"
}

object聲明也可以用來創建靜態方法。

open class MyFragment : Fragment() {
    companion object {
        fun newInstance(): MyFragment = MyFragment()
    }
}

上面的方法可以這樣調用val fragment = MyFragment.newInstance(),就和Java的靜態方法一樣。

接口

雖然Kotlin不支持多繼承, 但是還是支持接口的。只不過這個接口和Trait比較接近,可以在接口中包括默認實現。

interface SessionCloseable {
    fun closeSession() {
        Log.d(SessionCloseable::class.java.simpleName, "Closing...")
    }
}

以上接口定義了一個可以關閉session的方法,下面我們在一個activity里實現這個方法。

class KotlinActivity : Activity(), SessionCloseable {
    override fun onStop() {
        super.onStop()
        closeSession()
    }
}

有一點需要注意的是Kotlin里沒有extend和implement的區分,什么時候都是逗號分隔。

擴展(extension)

最后我們看一個例子:你可以給一個已經存在的類添加方法。

比如你要創建一個方法,這個方法可以把字符串的空白替換為下划線。在Java里你需要創建一個Utility的方法,以
原始字符串為參數。

public class StringUtils {
    public static String encodeString(String str) {
        return str.replaceAll(" ", "_");
    }
}

在Kotlin里,你可以創建一個擴展方法(extension function),即使原類是final的。

fun String.encodeSpaces(): String {
    return this.replace(" ", "_")
}

最后

為了公平起見,以上說到的大部分特性在Java8里都已經有了。但是這些什么時候可以在Android里用到可能
就遙遙無期了(其實這個問題已經有人在2014的Google I/O里問過了,但是根據Xavier Ducrohet的說法近期沒有這樣的計划)。
還好現在有Kotlin了。

另外,這個語言已經非常的成熟。唯一的問題就是文檔經常補全而且還經常是過期的,不過因為語法和同時JVM語言的Scala多少
有些接近,多少可以猜出個大概。所以,這只是一個很小的瑕疵。

最后的最后,Kotlin將會在我(作者)后續的Android開發中盡可能的使用。顯然,對已有的代碼做轉化不太明智。
而且Kotlin可以和Java的代碼無縫互操作,這樣不是什么太大的問題。Kotlin很值得一試!

原文地址, 代碼在這里


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM