Android開發(fā)者都知道,Google宣布Kotlin First,并且在Android官網(wǎng)上的Demo代碼都是Kotlin優(yōu)先,之后提供的代碼也是,推廣的決心很大。而且Kotlin和Java能100%兼容,并且語法更簡潔,后面我也會陸續(xù)寫一些Kotlin的分享文章,今天先概覽一下Kotlin的優(yōu)勢。
1.類型推斷
// 只讀變量聲明(更友好) 想想final
val a: Int = 1 // 后置類型聲明
// 一般利用類型推斷,思維更加順暢,不用再關心參數(shù)是什么類型的問題
val a = 5
val s = String()
val clazz = s.getClass()
val method = clazz.getDeclaredMethod("name", null)
// 可變變量聲明
var x = 5
2.View初始化
inline fun <reified TV:View> KView(context: Context, init: TV.() -> Unit) : TV {
val constructor = TV::class.java.getConstructor(Context::class.java)
val view : TV = constructor.newInstance(context)
view.init()
return view
}
>>> usage
val view = KView<TextView>(this) {
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT)
text = "Hello"
}
3.NUllPointer
空類型和非空類型
var age: String? = null
// 直接調(diào)用會編譯報錯
val age1 = age.toInt()
// 正確調(diào)用
val age1 = age?.toInt()
// 不做處理返回null
val age2 = age?.toInt()
// age為空返回-1
val age2 = age?.toInt() ?: -1
// 拋出空指針異常
val age2 = age!!.toInt()
val l = s?.length // s != null, l = s.length else l = null, l: Int?
val l = s!!.length // same as l = s.length in java, l: Int
val l = s?.length ?: 0 // s != null, l = s.length else l = 0, l: Int
return myValue ?: -1
// 鏈式使用:
bob?.department?.head?.name // 任一為null不執(zhí)行
Attention:
如果被Java調(diào)用,由于Java無法保證非空(除非已經(jīng)使用@NonNull注解注明),從Java接收的參數(shù)必須是可空的。
4. ? and Elvis
// java
if(view != null) {
if(view.getParent() != null) {
if(view.getParent() instanceof ViewGroup) {
((ViewGroup) view.getParent()).removeView(view)
}
}
}
// kotlin
(view?.parent as? ViewGroup)?.removeView(view)
5. when
when(x) {
in 1..10 -> print("x is in the range")
!in 10..20 -> print("x is outside the range")
is String -> print("x is a string")
else -> print("none of the above")
}
// usage
if(TextUtils.equals(day, today)) {
xxx1
} else if(TextUtils.equals(day, tomorrow)) {
xxx2
} else {
xxx3
}
// kotlin
when(day) {
today -> xxx1
tomorrow -> xxx2
else -> xxx3
}
6. 擴展函數(shù)
private fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp: T = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
>>> usage
val list = mutableListOf<Int>(1, 2, 3)
list.swap(0, 1)
println(list)
>>> out
[2, 1, 3]
7. 關鍵字object
單例
object KotlinPower {
override fun toString(): String {
return "KotlinPower"
}
}
>>> usage
println(KotlinPower.toString())
對象字面量
fun testObject() {
val a = object {
var x: Int = 0
var y: Int = 0
}
println("a.x: ${a.x}, a.y: ${a.y}")
}
>>> usage
testObject()
>>> out
a.x: 0, a.y: 0
再看一個例子:
object Test {
fun sayMessage(msg: String) {
println("from Kotlin $msg")
}
}
// kotlin code
Test.sayMessage("Hello")
// java code
Test.INSTANCE.sayMessage("hello");
如果要保持java和Kotlin中的調(diào)用方式一樣,可以在Kotlin中通過注解@JvmStatic方式
object Test {
@JvmStatic
fun sayMessage(msg: String) {
println("from Kotlin $msg")
}
}
//這樣在java中就可以直接
Test.sayMessage("Hello")
8. 屬性
引入了屬性的概念,隱式的getter與setter:
var stringRepresentation: String
get() = this.toString()
set(value) {
setDataFromString(value)
}
// 相當于
public String getStringRepresentation() {
return this.toString();
}
public void setStringRepresentation(String value) {
setDataFromString(value)
}
9.函數(shù)
在Kotlin中函數(shù)成為了一等公民,位置不需要一定在類的內(nèi)部,可以和類成為頂級函數(shù),函數(shù)也可以作為參數(shù)傳遞
- 缺省參數(shù),命名參數(shù)
可以簡化重載,不用再使用Builder等優(yōu)勢
fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
// do something
}
reformat(str)
reformat(str, wordSeparator = ' ') // 可以使用參數(shù)的名字給缺省參數(shù)賦值
// 可以通過@JvmOverloads注解生成Java的重載形式便于Java來調(diào)用
- 擴展函數(shù)
可以去掉Java中到處存在的XXXUtils.java類
// Java
// 寫一個Util類,作為參數(shù)傳進去
public class ViewUtils {
public static int findColor(View view, int resId) {
return view.getResources().getColor(resId);
}
}
ViewUtils.findColor(view, resId);
使用Kotlin簡化如下:
fun View.findColor(id: Int) : Int {
return this.resources.getColor(id)
}
view.findColor(resId)
一系列這種類型的Java工具類在Kotlin中被“改造”成了擴展方法例如:
Collection.sort(list)在Kotlin中直接list.sort()就可以了。
可以完全取代以往的Util類。
10.作用域函數(shù)
- let/run
對象作為參數(shù)傳入lambda(run則作為this),返回值為lambda表達式的返回值, 常見場景:轉(zhuǎn)換類型,處理nullable類型
// if...else...寫法
private fun testIfElse(): Object? {
return if (a !== null) {
val b = handleA(a)
if (b !== null) {
handleB(b)
} else {
null
}
} else {
null
}
}
// ?.let寫法
private fun testLet(): Object? {
return a?.let { handleA(it) }?.let { handleB(it) }
}
- apply
對象作為this傳入lambda, 返回值為對象本身,常見場景:初始化對象
- also
對象作為參數(shù)傳入lambda,返回值為對象本身,常見場景:鏈式調(diào)用中的副作用
// transforming data from api with intermediary variable
val rawData = api.getData()
Log.debug(rawData)
rawData.map { /** other stuff */ }
// use 'also' to stay in the method chains
api.getData()
.also { Log.debug(it) }
.map { /** other stuff */ }
- takeIf/takeUnless
對象作為參數(shù)傳入lambda,返回值為對象本身或null(根據(jù)lambda中語句的true or false),常見場景:鏈式調(diào)用形式的條件判斷
File(url).takeIf { it.exists() }
?.let {
JSONObject(NetworkUtils.postFile(20 * 1024, "http://i.snssdk.com/2/data/upload_image/", "image", url))
}?.takeIf { it.optString("message") == "success" }
?.let {
post(content, contact, it.optJSONObject("data")?.optString("web_uri"))
} ?: mHandler.post { view?.onFail() }
11.Lambda
本質(zhì)上是一個匿名方法(單方法接口)
fun isGreaterThanZero(n: Int): Boolean {
return n > 0
}
collection.filter(::isGreaterThanZero)
// 使用Lambda
collection.filter{ i: Int -> i > 0 }
collection.filter{ i -> i > 0 }
collection.filter{ it > 0 }
單方法接口都可以傳Lambda:
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showToast();
}
});
button.setOnClickListener{ showToast() }
內(nèi)置常用的流處理Lambda:
names
.filter{ it.startsWith("A") }
.sortedBy{ it }
.map{ it.toUpperCase() }
.forEach{ print(it) }
12.其他
- 支持運算符重載
- 接口可以有缺省方法
-
Data Class數(shù)據(jù)類型,自動實現(xiàn)`equals/hashCode/toString - 協(xié)程
- 伴生對象
Refs: