Kotlin, Android的Swift
來自: http://www.cnblogs.com/sunshine-anycall/p/5223158.html
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很值得一試!