Kotlin Power

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. 屬性

引入了屬性的概念,隱式的gettersetter

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ù)傳入lambdarun則作為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:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容