應用
-
空類型安全
Kotlin引入了可空類型(用排抬?標識)竖般,在編譯期杜絕了可空類型直接調用方法的可能。
var a: String = "abc" a = null // 編譯錯誤 var b: String? = "abc" b = null // ok val l = a.length val l = b.length // 錯誤:變量“b”可能為空 val l = b?.length ?: 0
-
鏈式調用
靈活使用Kotlin提供的let洞渔、apply赊淑、takeIf這些方法国旷,用鏈式調用的方式組織代碼误趴,可以將一大串邏輯分割成幾塊。
File(url).takeIf { it.exists() } ?.let { JSONObject(NetworkUtils.postFile(SERVER_URL, url)) }?.takeIf { it.optString("message") == "success" } ?.let { post(it.optString("result")) } ?: mHandler.post { view?.onFail() }
-
默認參數
普通的帶有默認參數的方法Java是無法調用的蓬抄,因為Kotlin對默認參數的處理并不是生成多個方法丰嘉,而是給方法添加幾個額外參數記錄調用者傳遞了多少參數,加上了JvmOverloads這個注解之后才會生成多個方法供Java調用嚷缭。并且Kotlin調用方法可以指定參數名饮亏。
class CustomLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr), LifeCycleMonitor { // pass }
-
擴展方法
擴展方法在項目里使用得比較少,但是Kotlin提供的很多語法糖都是利用擴展方法實現的阅爽,例如forEach路幸、let之類的方法。擴展方法的原理是生成一個靜態(tài)方法付翁。
// _Collections.kt里的擴展方法 /** * Performs the given [action] on each element. */ @kotlin.internal.HidesMembers public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit { for (element in this) action(element) }
-
操作符重載
Kotlin會將一些常用的表達式翻譯為方法調用劝赔,最常用的有將 list[0] 翻譯成 list.get(0) ,將 map[0] = someObject 翻譯成 map.set(0, someObject)胆敞。實際上任意實現operator fun get(a : Any) : Any 和 operator fun set(a : Any, b : Any) 方法的類都可以使用以上兩種表達式着帽。
// 操作符重載在Kotlin的語法中隨處可見,下面這個例子說明了 for (i in 1..10) { // pass } // 是如何工作的移层,首先明白表達式 .. 對應 rangeTo 方法仍翰,表達式 in 對應 contains 方法 // 在Primitives.kt文件中的Int類里 /** Creates a range from this value to the specified [other] value. */ public operator fun rangeTo(other: Int): IntRange // 在IntRange類里可以發(fā)現 in 這個表達式對應的方法調用 contains public class IntRange(start: Int, endInclusive: Int) : IntProgression(start, endInclusive, 1), ClosedRange<Int> { override val start: Int get() = first override val endInclusive: Int get() = last override fun contains(value: Int): Boolean = first <= value && value <= last
-
不再使用findViewById
在build.gradle中添加 apply plugin:'kotlin-android-extensions' 就可以直接在代碼中用View的id來代替這個View對象。
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) iv_feedback.setOnClickListener(this) iv_back.setOnClickListener(this) btn_feedback.setOnClickListener(this)
反編譯發(fā)現观话,這種用法的原理是Kotlin會自動生成findViewById的代碼予借,在Activity、Fragment和自定義View中Kotlin會使用一個map緩存每次查找到的View频蛔,避免每次調用View的方法都會重新調用一次findViewById灵迫,但是需要注意的是通過View.id這種方式獲取子View的時候沒有緩存,所以在RecyclerView的ViewHolder中都會使用一個屬性來存儲ItemView的某個子View晦溪。
// Activity中的邏輯 public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { // Fragment的代碼中這里會調用getView.findViewById瀑粥,所以通過id調用方法需要在onCreateView生命周期之后使用 var2 = this.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } // RecyclerView的ViewHolder中都會使用一個屬性來存儲ItemView的某個子View private val mLabelImage = itemView.label_image private val mLabelType = itemView.label_type
-
與屬性相關的一些改變
-
自帶getter/setter
Kotlin類里的屬性自帶getter/setter,訪問權限可以修改三圆,也可以重寫get/set方法
var someString : String get() = "this${toString()}" protected set(value) { Log.e(TAG, "setValue$value") field = value }
-
可以定義在類聲明里
open class Message(val id: Long, val type: Int, val time: Long, val status : Int)
-
lateInit和by lazy
對于一些沒有在構造函數里賦值的非空類型對象狞换,可以使用lateinit和by lazy來延遲初始化。
坑
Java調用Kotlin方法時空類型不再安全
Java里調用kotlin方法舟肉,空對象傳遞給Kotlin的非可空參數會拋異常修噪,但是Kotlin無法判斷Java傳遞的對象是否可能為空,所以編譯器不會報異常路媚。在將Java工程轉變成Kotlin工程的過程中不能忽略這個坑黄琼。
更多
協(xié)程
Anko Layouts代替xml
verticalLayout {
val name = editText()
button("Say Hello") {
onClick { toast("Hello, ${name.text}!") }
}
}