Kotlin入門(一) —— 基本篇+函數(shù)篇

1. Kotlin介紹

  • 基于JVM??梢耘cJava進(jìn)行混合開(kāi)發(fā)和相互調(diào)用。
  • 由JetBrains開(kāi)發(fā)。系出名門,也得到其IDE的良好支持。
  • Android官方支持開(kāi)發(fā)語(yǔ)言。
  • 更簡(jiǎn)潔,擁有各種語(yǔ)法糖。
  • 更安全,對(duì)空安全等進(jìn)行了優(yōu)化處理。

2. Kotlin環(huán)境

# 項(xiàng)目build.gradle
buildscript {
    ext.kotlin_version = '1.1.4-3'
    
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

# 模塊build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
}

3. kotlin-android-extensions

和ButterKnife說(shuō)再見(jiàn)

  • 當(dāng)然不用findViewById
  • 也不用定義空間變量
  • 甚至不用ButterKnife.bind
<Button
    android:id="@+id/close_button"
    android:text="關(guān)閉"
    android:layout_alignParentEnd="true"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
import kotlinx.android.synthetic.main.main_activity.view.*

class MyActivity : Activity() {
     override fun onCreate(savedInstanceState: Bundle?) {
        setContentView(R.layout.main_activity)
        close_button.setOnClickListener { mPresenter?.exit() }
     }
}

4. Anko

  • Anko Commons: 一個(gè)輕量級(jí)的Helper用于處理 intents, toast, dialogs, logging等等;
  • Anko Layouts: 一種可輕量級(jí),可快速開(kāi)發(fā)的動(dòng)態(tài)Android layouts。用代碼寫(xiě)layout而不是xml;
  • Anko SQLite: a query DSL and parser collection for Android SQLite;
  • Anko Coroutines: utilities based on the kotlinx.coroutines library.
以Anko Layouts和Anko Commons舉例

在onCreate中使用以下代碼可以同時(shí)實(shí)現(xiàn)layout和setContentView

verticalLayout {
    val name = editText()
    button("Say Hello") {
        onClick { toast("Hello, ${name.text}!") }
    }
}
image
image

5. 數(shù)據(jù)類型與等式

首先,Kotlin沒(méi)有基本數(shù)據(jù)類型,所有變量包括所謂的基本數(shù)據(jù)類型在內(nèi),都是對(duì)象。
其次,Kotlin中有兩種相等:
  • 參照相等:指向同一個(gè)對(duì)象 使用 === !==判斷
  • 結(jié)構(gòu)相等:使用== !=判斷,相當(dāng)于 a?.equals(b) ?: b === null 可見(jiàn)
裝箱:可空標(biāo)識(shí)(比如說(shuō) Int?) 或者涉及泛型,數(shù)值都會(huì)被裝箱。裝箱過(guò)的數(shù)值已經(jīng)不保留先前的引用關(guān)系
val a: Int = 10000
print (a === a ) //打印 'true'
val boxedA: Int? =a
val anotherBoxedA: Int? = a
print (boxedA === anotherBoxedA ) //注意這里打印的是 'false'
print (boxedA == anotherBoxedA) // Prints 'true'

6. collection 和 字符串

kotlin-stdlib / kotlin.collections
  • Array:用于取代Java的數(shù)組。
  • List:用于取代Java的List
  • Map: 用于取代Java的Map
// 通過(guò)指定Array大小并提供一個(gè)迭代器
// 創(chuàng)建一個(gè) Array<String>  內(nèi)容為 ["0", "1", "4", "9", "16"]
val asc = Array(5, {i -> (i * i).toString() })

val nullArray : Array<Int?> = arrayOfNulls(3) // 創(chuàng)建一個(gè)指定大小的空Array
val list = listOf("a", "b", "c")
val x: IntArray = intArrayOf(1, 2, 3)
val map = mapOf("a" to 1, "b" to 2, "c" to 3)
Kotlin 有專門的類來(lái)表示原始類型從而避免過(guò)度裝箱: ByteArray, ShortArray, IntArray 等等。這些類與 Array 沒(méi)有繼承關(guān)系,但它們有一樣的方法與屬性。
String
// 包含轉(zhuǎn)義符的字符串
val s = "Hello World!\n"
// 不包含轉(zhuǎn)義符的字符串,但不能包含3個(gè)及以上的"
val text = """
    for (c in "foo")
        print(c)
"""

// 模板
val s = "abc"
val str = "$s.length is ${s.length}" //識(shí)別為 "abc.length is 3"

8. Ranges

  • 范圍主要用于 if in (范圍) 和 for in (級(jí)數(shù)) 中使用,判斷變量是否處于某個(gè)范圍或遍歷某個(gè)范圍
  • 使用 .. 操作符來(lái)或者一些特有操作符來(lái)定義
// if in
if (i in 1..10)  println(i)
if (x !in 1.0..3.0) println(x)
if (str in "island".."isle") println(str)

// for in
for (i in 1..4) print(i) // prints "1234"
for (i in 4..1) print(i) // prints nothing
for (x in 1.0..2.0) print("$x ") // prints "1.0 2.0 "
for (str in "island".."isle") println(str) // error: string range cannot be iterated over

// 特有操作符
// rangeTo
// 與 .. 相同

// downTo
for (i in 4 downTo 1) print(i)

// step 必須大于0
for (i in 1.0..2.0 step 0.3) print("$i ") // prints "1.0 1.3 1.6 1.9 "

// reversed
for (i in (1..4).reversed()) print(i) // prints "4321"

范圍和技術(shù)主要通過(guò)以下兩個(gè)接口實(shí)現(xiàn)

interface Range<T : Comparable<T>> {
    val start: T
    val end: T
    fun contains(Element : T): Boolean
}

interface Progression<N : Number> : Iterable<N> {
    val start : N
    val end : N
    val increment : Number
}

// if increment > 0
for (int i = start; i <= end; i += increment) {
  // ...
}

// if increment < 0
for (int i = start; i >= end; i += increment) {
  // ...
}

9. 空安全和類型轉(zhuǎn)換安全

var a: String ="abc"
a = null //編譯錯(cuò)誤 

var b: String? = "abc"
b = null
val l = b.length() //錯(cuò)誤:b 不可為空
val l = if (b != null) b.length() else -1 // 類型經(jīng)過(guò)檢查后可以安全飲用
val l = b.length() ?: -1 // = ?: 空安全三元操作符
val name = node.getName() ?: throw IllegalArgumentException("name expected")  // Throw return

// 安全調(diào)用 避免NullPointerException
b?.length()

val l = b !!.length()

// 不安全轉(zhuǎn)換 有可能拋出ClassCastException
val x: String = y as String
// 安全轉(zhuǎn)換 避免ClassCastException
val aInt: Int? = a as? Int

10. 流程控制

val max = if (a > b){
    print("Choose a")
    a
}
else{
    print("Choose b")
    b
}

// 用于代替switch if-else的when
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { //Note the block
        print("x is neither 1 nor 2")
    }
}

// 當(dāng)有兩個(gè)case使用同樣方法時(shí)
when (x) {
    0,1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

// 用表達(dá)式作為case
when (x) {
    parseInt(s) -> print("s encode x")
    else -> print("s does not encode x")
}

// 用范圍作為case
when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

// 類型檢查作為case
val hasPrefix = when (x) {
    is String -> x.startsWith("prefix")
    else -> false
}

// return 控制打斷范圍
foo outer() {
    foo inner() {
        return@outer
    }
}

11. 函數(shù)

使用中綴符號(hào)調(diào)用函數(shù) 成員函數(shù)和擴(kuò)展函數(shù)都適用

//給 Int 定義一個(gè)擴(kuò)展方法
infix fun Int.shl(x: Int): Int {
...
}

1 shl 2 //用中綴注解調(diào)用擴(kuò)展函數(shù),與下一句等效
1.shl(2)

使用默認(rèn)參數(shù)減少重載

可以命名參數(shù),當(dāng)參數(shù)較多時(shí)更方便設(shè)置參數(shù),可讀性更強(qiáng)

fun reformat(str: String, normalizeCase: Boolean = true,upperCaseFirstLetter: Boolean = true,
             divideByCamelHumps: Boolean = false,
             wordSeparator: Char = ' ') {
...
}
reformat(str, true, true, false, '_')
reformat(str, wordSeparator = '_')

12. 高階函數(shù)與lambda

高階函數(shù)就是可以接受函數(shù)作為參數(shù)并返回一個(gè)函數(shù)的函數(shù)。

fun lock<T>(lock: Lock, body: () -> T ) : T {
    lock.lock()
    try {
        return body()
    }
    finally {
        lock.unlock()
    }
}

// 函數(shù)作為參數(shù)傳入
fun toBeSynchroized() = sharedResource.operation()
val result = lock(lock, ::toBeSynchroized)

// lambda表達(dá)式傳入
val result = lock(lock, { sharedResource.operation() })
  • lambda中,如果參數(shù)只有一個(gè),可以不寫(xiě)出來(lái),在函數(shù)體中用it來(lái)表示
  • 如果函數(shù)的參數(shù)只有一個(gè)函數(shù),則括號(hào)可以不寫(xiě),直接寫(xiě)lambda
fun <T, R> List<T>.map(transform: (T) -> R): List<R> {
    val result = arrayListOf<R>()
    for (item in this)
        result.add(transform(item))
    return result
}

// 調(diào)用
val doubled = ints.map {it -> it * 2}
// 簡(jiǎn)化
val doubled = ints.map { it * 2 }
此外,字面函數(shù)或函數(shù)擴(kuò)展還可以作為屬性變量而存在
val sum = {x: Int,y: Int -> x + y}
// 以下為完全寫(xiě)法
val sum: (Int, Int) -> Int = {x, y -> x+y }

// 函數(shù)擴(kuò)展
val sum = fun Int.(other: Int): Int = this + other

// 函數(shù)擴(kuò)展在參數(shù)中的聲明如下
sum : Int.(other: Int) -> Int

13. 標(biāo)準(zhǔn)庫(kù)

類似JDK提供的一系列標(biāo)準(zhǔn)庫(kù),Kotlin也提供了以下標(biāo)準(zhǔn)庫(kù),可供參考
包名 信息
kotlin 核心函數(shù)和類型,在所有支持平臺(tái)均可用
kotlin.browser 訪問(wèn)并操作瀏覽器 DOM 的 API
kotlin.concurrent 并發(fā)編程的函數(shù)集合
kotlin.dom 用在 W3C DOM 的函數(shù)
kotlin.io 用于文件和流的 IO API
kotlin.jvm 專門用于 java 平臺(tái)的函數(shù)和注解
kotlin.math 數(shù)學(xué)反面的 API
kotlin.platform 用于自定義 Kotlin 編譯器生成的代碼,使其在目標(biāo)平臺(tái)上更好的交互
kotlin.properties 實(shí)現(xiàn)泛型和泛型屬性的標(biāo)準(zhǔn)并幫助函數(shù)實(shí)現(xiàn)自定義泛型
kotlin.reflect Kotlin reflection 運(yùn)行時(shí) API
kotlin.reflect.jvm 用于 Kotlin reflection 和 java 交互的運(yùn)行時(shí) API
kotlin.support
kotlin.test 寫(xiě)測(cè)試用例的 API
kotlin.text 用于正則表達(dá)式和文字的函數(shù)
kotlin.util 實(shí)用函數(shù)

14. 尚未談及

本期文章中還有些尚未提及的知識(shí)點(diǎn),如有興趣還可以自行查閱
  • 動(dòng)態(tài)類型
  • 反射
  • 注解
  • 運(yùn)算符重載
  • 內(nèi)聯(lián)函數(shù)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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