1 JetBrains 親兒子,Google 干兒子
Kotlin 由大名鼎鼎的 JetBrains 開發(fā)維護(hù),并且得到了 Google 的官方認(rèn)可痢毒,可謂是 JetBrains 的親兒子,Google 的干兒子运怖,據(jù)說 Google 還在最新的 Android P 上,在虛擬機(jī)層對 Kotlin 進(jìn)行了專門的性能優(yōu)化。
2 Kotlin 和 Java 完全兼容
Kotlin 和 Java 一樣都是基于 JVM 的語言,所以他們倆其實(shí)就是親兄弟因谎,自然也不存在什么兼容性問題,Java 的 API 在 Kotlin 里會被自動轉(zhuǎn)換成 Kotlin 語法颜懊,反過來 Kotlin 的 API 在 Java 里也會自動轉(zhuǎn)換成 Kotlin 語法财岔,所以你完全不需要擔(dān)心什么兼容性問題。
關(guān)于兩個語言是如何相互轉(zhuǎn)換的河爹,我猜測都是通過字節(jié)碼進(jìn)行解析然后轉(zhuǎn)換的匠璧,僅僅是猜測而已。
3 跟 setter 和 getter 說再見
據(jù)說我們這輩子擼過最多的代碼是 setter 和 getter咸这?因為你得為數(shù)據(jù)封裝類的每一個字段寫 setter 和 getter夷恍,機(jī)智一點(diǎn)的會使用 IDE 生成代碼,而 Kotlin 則一句話就搞定了媳维。
比如我們要寫一個 Person 的數(shù)據(jù)封裝類酿雪,用 Java 的話我們會這樣寫:
public class Person {
private String name;
private String addr;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAddr(String addr) {
this.addr = addr;
}
public String getAddr() {
return addr;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
這段 Java 代碼看起來是不是又臭又長,我們換 Kotlin 寫個 Person 類看看:
data class Person(var name: String, var addr: String, var age: Int)
什么侄刽!這就完了嗎指黎?沒錯這就完了,你需要的 setter 和 getter 方法 Kotlin 都已經(jīng)為你自動生成了州丹!
4 參數(shù)很多看著懵逼醋安?
如果一個方法有很多參數(shù),在調(diào)用的時候難免會出現(xiàn)看不出每個參數(shù)是什么意思的情況墓毒,尤其是傳遞數(shù)字的時候吓揪,比如我們有下面一個方法:
public Rectange createRectange(int x, int y, int width, int height) {}
我們在調(diào)用的時候這樣寫:
createRectangle(20, 30, 40, 50);
什么鬼!對 API 不熟悉的人根本沒辦法一眼看出這個方法調(diào)用傳遞的參數(shù)都是什么意思蚁鳖!我們換 Kotlin 寫個看看:
fun createRectangle(x: Int, y: Int, width: Int, height: Int) {}
Kotlin 允許我們在調(diào)用方法的時候顯式指定參數(shù)的名稱磺芭,如下所示:
createRectangle(x = 20, y = 30, width = 40, height = 50)
怎么樣赁炎!是不是看起來清晰多了醉箕,一眼就看出在坐標(biāo)為 (20, 30) 的位置創(chuàng)建一個寬 40,高 50 的矩形徙垫。
5 跟方法重載說再見
如果一個方法有 N 個參數(shù)讥裤,并且有些參數(shù)是可選的,你是不是要為它寫好幾個重載版本姻报,當(dāng)讓你也可以用 Builder 解決該問題己英,不管哪一種方式我都要多寫很多代碼啊吴旋!在 Kotlin 中你可以給每一個參數(shù)指定默認(rèn)值损肛,具有默認(rèn)值的參數(shù)可以在調(diào)用的時候選填厢破,是不是很爽!
我們來看下面這個 Java 方法:
public void foo() {
foo(0, 0, 0)
}
public void foo(int a) {
foo(a, 0, 0)
}
public void foo(int a, int b) {
foo(a, b, 0)
}
public void foo(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
再來看看 Kotlin 的寫法:
fun foo(a: Int = 0, b: Int = 0, c: Int = 0) {}
搞定了治拿!我們來看看這方法怎么調(diào)用:
foo()
foo(a = 1)
foo(b = 2)
foo(c = 3)
foo(a = 1, b = 2)
foo(a = 1, b = 2, c = 3)
6 用 as 代替 () 進(jìn)行類型轉(zhuǎn)換
如果你是 Android 開發(fā)者摩泪,相信你一定對 findViewById()
方法不陌生吧,在獲取每一個 View 的時候都需要進(jìn)行類型轉(zhuǎn)換劫谅,如下所示:
Button button = (Button) findViewById(R.id.button);
ImageView imageView = (ImageView) findViewById(R.id.image_view);
這樣的類型轉(zhuǎn)換方式本身沒什么問題见坑,但是 Kotlin 有更優(yōu)雅的類型轉(zhuǎn)換關(guān)鍵字 as
:
Button button = findViewById(R.id.button) as Button;
ImageView imageView = findViewById(R.id.image_view) as Button;
兩種方式比較起來,個人更喜歡 Kotlin 的方式捏检,原因如下:
- 用
as
代替()
更加具有可讀性 - 敲代碼的時候打
as
比打()
更快ヾ(?`Д′?)
7 讓方法重寫或?qū)崿F(xiàn)更明顯
我們來看下面這段代碼:
public class A extends B {
public void foo() {
}
}
如果我告訴你 A 的 foo()
方法是重寫 B 的 foo()
方法荞驴,你會怎么想?反正我是想罵人了贯城,標(biāo)記重寫方法的 @Override
被狗吃了嗎熊楼?這樣的寫法雖然編譯器不會報錯,但是卻不利于代碼的閱讀能犯,很容易讓人誤以為 foo()
方法是 A 自己新定義的孙蒙。在 Kotlin 中則不允許你這樣寫,它要求你必須顯式聲明某一個方法是重寫父類或接口的:
class A: B() {
override fun foo() {
}
}
有了 override
這個關(guān)鍵字悲雳,我們一看就知道這是一個重寫的方法挎峦。
8 支持類的方法擴(kuò)展
Kotlin 支持對一類進(jìn)行方法擴(kuò)展,注意這個擴(kuò)展并不是通過繼承合瓢,也就是它可以擴(kuò)展一個 final 類坦胶。例如我們可以擴(kuò)展 String 類,添加一個 log(tag: String)
方法晴楔,讓它可以在日志系統(tǒng)里面輸出自己的內(nèi)容:
fun String.log(tag: String) {
Log.d(tag, this)
}
然后我們就可以這么用:
val myString: String = 'test'
myString.log(TAG)
上面的 String 擴(kuò)展很無聊顿苇,我們來一個逼格高一些的,例如我們可以擴(kuò)展 SharedPreferences 類的 edit()
方法税弃,讓它支持更便捷的便捷方式:
fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
action(editor)
editor.apply()
}
然后我們就可以這么用:
val sp = getSharedPreferences("name", Context.MODE_PRIVATE)
sp.edit({
putInt("key1", 0)
putLong("key2, 1)
putString("key3", "value")
})
沒錯纪岁,你不需要調(diào)用 apply()
或者 commit()
方法,因為我們的擴(kuò)展方法里面做好了则果,你要做的就是存儲數(shù)據(jù)幔翰。
9 媽媽再也不用擔(dān)心我空指針了
空指針異常是我們經(jīng)常遇到的問題,為什么會出現(xiàn)空指針西壮?要嘛是忘記進(jìn)行判空處理遗增,要嘛就是忘記賦值。當(dāng)然在開發(fā)過程中可以使用 @Nullable 注解來對可能為空的變量或方法返回值進(jìn)行注解款青,但是這樣當(dāng)你沒有進(jìn)行判空的時候做修,也僅僅是收到 IDE 的一個警告信息而已,照樣能夠正常編譯。
在 Kotlin 的語法里饰及,你必須顯示聲明成員變量蔗坯、方法參數(shù)、方法返回值是否可以為空燎含,當(dāng)你在使用一個可能為空的成員變量時沒有進(jìn)行判空處理步悠,編譯器直接就會報錯,而不是形同虛設(shè)的警告瘫镇。下面是一段簡單的代碼鼎兽,通過 ?
關(guān)鍵字聲明成員變量 name
可能為空,然后我們在使用的時候必須判空:
var name: String? = null
if (name != null) {
// do something
}
10 一句話實(shí)現(xiàn)單例模式
當(dāng)例模式是我們經(jīng)常用到的一個設(shè)計模式铣除,其目的就是為了讓全局只有一個對象實(shí)例谚咬,在 Java 里面我們會這么寫:
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {}
}
在 Kotlin 里面則更加簡單,只需要通關(guān)鍵字 object
就可以生命一個類為單例:
object Singleton {}
11 讓你的代碼僅在模塊內(nèi)可見
有過 SDK 開發(fā)經(jīng)驗的人應(yīng)該會遇到這樣一個問題尚粘,在開發(fā)過程中我們經(jīng)常會將類按照功能進(jìn)行分包择卦,例如 A 屬于com.xxx.pkga,B 屬于 com.xxx.pkgb郎嫁,但是我們又希望 A 的 foo()
方法可以被 B 訪問秉继,但是不被 SDK 之外的其他人訪問,這種情況在 Java 里面是無解的泽铛,要嘛你聲明 foo()
方法為 public
尚辑,要嘛你把 A 和 B 放在一個包下,并聲明 foo()
方法為 default
盔腔,但是這兩種做法都違背了我們的意愿杠茬。在 Kotlin 里面,專門提供了 internal
關(guān)鍵字弛随,用于聲明一個類或方法只有模塊內(nèi)部可見瓢喉,所謂的模塊在 Android Studio 里面就是一個 Gradle Module,而我們的 SDK 通常都是一個 Module舀透,這就完美解決了上面描述的問題了栓票。
12 比 // TODO 更狠的 TODO()
你是不是經(jīng)常寫了個 // TODO
注釋然后放在那邊幾百年不動它?好吧這不能怪你愕够,因為它只是一段注釋而已走贪,不會主動提示你“快來把我解決掉!”链烈,而 Kotlin 給我提供了一個更給力的方式 TODO()
方法厉斟,用它在代碼中標(biāo)記那些你日后會去處理的邏輯挚躯,并且當(dāng)你跑到這段沒有完成邏輯處理的代碼時强衡,TODO()
會這樣告訴你“來啊码荔!干掉我颁銮凇感挥!不然我就讓你崩潰!”:
fun foo() {
TODO("來霸桨堋触幼!干掉我啊究飞!不然我就讓你崩潰置谦!")
}
其內(nèi)部實(shí)現(xiàn)原理也很簡單,就是給你拋異常亿傅,但是起碼我不用自己寫啦媒峡,而且它默認(rèn)就是引入的:
/**
* Always throws [NotImplementedError] stating that operation is not implemented.
*/
@kotlin.internal.InlineOnly
public inline fun TODO(): Nothing = throw NotImplementedError()
13 更加靈活的字符串定義
用 Java 拼接字符串是不是很惡心?比如我們要拼接一串 SQL 查詢語句葵擎,用 Java 會這么寫:
String table = ...
String id = ...
String email = ...
String age = ...
String sql = "SELECT * FROM " + table + " WHERE id=" + id + " AND name=" + name + " AND email=" + email + " AND age=" + age;
使用一堆的 +
拼接起這個查詢語句谅阿,它的可讀性真是不敢恭維,而且寫起來也不方便酬滤,我們用 Kotlin 的字符串模板試試:
val table = ...
val id = ...
val email = ...
val age = ...
val sql = "SELECT * FROM $table WHERE id=$id AND name=$name AND email=$email AND age=$age"
在字符串中的 $table
签餐、$id
、$name
盯串、$email
和 $age
會被自動替換為同名變量的值氯檐,再也不需要使用一堆 +
去拼接字符串啦,如果你想讓語句看起來更好看些体捏,可以這么寫:
val table = ...
val id = ...
val email = ...
val age = ...
val sql = """
SELECT * FROM $table
WHERE id=$id
AND name=$name
AND email=$email
AND age=$age
"""
在 Kotlin 中字符串除了用 "字符串"
表示之外男摧,還可以用 """字符串"""
表示,這種方式讓你在定義字符串的時候隨意換行并且保留格式译打。
持續(xù)更新中...