充分理解Kotlin,快速上手寫業務

前言

即便天天10點下班,即便需求不少,我也要用這腐朽的聲音喊出:我要學習,我要寫文章!!java

幾個特性,快速上手Kotlin面試

充分理解Kotlin,快速上手寫業務app

快速切換至Kotlin for Android模式ide

聊一聊Kotlin中的協程,真香函數

又是一篇Kotlin的文章,爲啥...還不是由於工做須要。毫無疑問,最好的學習方式是經過官方文檔去學習。不過我的以爲官方文檔多多少少有一些不夠高效。post

中文官方文檔學習

所以這篇是從我學習的我的視角以文檔的形式去輸出Kotlin語言基礎的學習。 不扯淡了,開整。ui

正文

高階函數

高階函數是將函數用做參數或返回值的函數。this

我的爲何把這個語言特性放在第一位,由於我以爲這是咱們Java語言中所不支持的。然而這個特性基本貫穿整個Kotlin語言體系。因此我的把它放到了第一位,也但願各位小夥伴可以重視這個小小的特性。先看看一個小小的demo,感覺一下這個特別特性:spa

// 函數定義
fun funtion(num: Int, innerFun: (Int) -> Int): Int {
    return innerFun(num)
}
複製代碼

簡單解釋一下上邊的代碼。咱們先看函數定義,這裏定義了一個名爲funtion而且返回值爲Int的函數,此外這個函數接受一個Int參數和一個函數類型的參數(這個函數須要傳遞一個Int參數,而且返回一個Int值)。 接下來咱們調用一下:

// 函數調用
val result = funtion(1) {
	it + 666
}
複製代碼

對於Lambda來講,入參若是是一個的話能夠用it來表示

說實話,第一次我看到這種調用的時候,是一臉懵逼的。不知道剛入坑的小夥伴是否是和我同樣的感覺?由於這種寫法包含小tips: 咱們的innerFun是能夠被簡化爲一個Lambda,而當Lambda做爲函數的最後一個參數時,是能夠將其寫在函數以外的。也就是Demo中的funtion(1){}。

此外咱們要注意一點,這裏咱們的函數實例,並無return,這是由於。lambda 表達式中的最後一個表達式是返回值 實際上這就是至關於調用了funtion方法的倆個參數,我們換一種傳統的寫法,兩者是等價的:

val inner = fun(num: Int): Int {
	return num + 1
}
val result = funtion(1, inner)
複製代碼

OK,接下來我們趁熱打鐵,再感覺感覺函數操做的「騷操做」。接下來咱們看一看其實狀況下的用法:

// 函數定義1
fun funtion(num: Int, innerFun: (Int, Int) -> Int): Int {
    return innerFun(num, num + 1)
}
// 函數調用1(上文提到,入參爲1個能夠用it表示,那麼倆個或者多個呢?咱們能夠以下,自定義)
val result = funtion(1) { num1, num2 ->
    num1 + num2 + 666
}
// 函數調用2(除了Lambda的調用方式,咱們還能夠用匿名函數,兩者是同樣的)
val result = funtion(1, fun(num1: Int, num2: Int): Int {
	return num1 + num2 + 666
}
複製代碼

OK,關於高階函數的內容,就聊這麼多,由於有了這個其實,不少內容也就很好上手了。接下來就讓咱們一同看看基於高階函數的內置封裝。

操做符

集合操做符

我的以爲,Kotlin操做符中。開發中頗爲經常使用的是集合操做符,好比咱們有時須要對一些數據進行連續的轉化,咱們可能會使用RxJava;

Observable.create(new ObservableOnSubscribe<List<CustomModel>>() {
            @Override
            public void subscribe(ObservableEmitter<List<CustomModel>> e) throws Exception {
                // 省略構建List<CustomModel>
                e.onNext(data);
            }
        }).flatMap(new Function<List<CustomModel>, ObservableSource<CustomModel>>() {
            @Override
            public ObservableSource<CustomModel> apply(List<CustomModel> customModels) throws Exception {
                return Observable.fromIterable(customModels);
            }
        }).map(new Function<CustomModel, String>() {
            @Override
            public String apply(CustomModel customModel) throws Exception {
                return customModel.name;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                // 操做s
            }
        });
複製代碼

這裏簡單,寫了一個RxJava的Demo:咱們有一個List集合,先把它一個個發送,而後把每個數據轉成String,最後去String進行處理。 而在Kotlin中,應對上述的需求,咱們該怎麼作?因爲操做符的支持,咱們能夠極爲方便的進行這類操做:

val data = arrayListOf<CustomModel>(// ...省略構建的過程)
val newData=data.map {
    it.name
}.forEach {
    // 操做it
}
複製代碼

用法很簡單,乍一看很唬人。可是其實很簡單,回憶一下咱們再開篇奠基的高階函數的基礎。這裏其實就是調用了data的擴展函數map(拓展函數是一種語法,能夠拓展示有的類。好比這個map就是拓展了Iterable,下文咱們會展開它的實現)。對它進行類型轉變,而後進而調用forEach自動對這個集合進行遍歷。

接下來讓咱們點進去,看一看具體的實現:

// 注意看,這裏map的**返回值**,是一個List<R>,也就是說最終將返回map後的類型集合。所以咱們能夠繼續進行鏈式調用。
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
    return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}

public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(destination: C, transform: (T) -> R): C {
    for (item in this)
        destination.add(transform(item))
    return destination
}
複製代碼

說白了,這裏的集合操做符就是把轉化的實現經過參數的形式暴露出來,由咱們自行去處理,其餘的事情,有內部封裝去作。 固然,這其中還有不少有趣的操做符,各位小夥伴能夠自行去了解。不過原理都是大同小異~

做用域函數

上述咱們聊的是做用在集合上的操做符,說白了。它們就是拓展在對應集合類上的函數而已。那麼可能有小夥伴會問,有沒有做用在對象上的?沒錯,是有的。也就是咱們接下來要聊的:做用域函數

其實很常見:

"Kotlin".let{
	it.toInt()
}
"Kotlin".run{
	this.toInt()
}

"Kotlin".apply{
}
"Kotlin".also{
}

public inline fun <T, R> T.let(block: (T) -> R): R
public inline fun <T, R> T.run(block: T.() -> R): R

public inline fun <T> T.apply(block: T.() -> kotlin.Unit): T
public inline fun <T> T.also(block: (T) -> kotlin.Unit): T

複製代碼

我們看一下,它們哥四個的定義,其實很清晰。這裏以返回值的類型,倆倆分類:

  • let/run。這倆個函數均可以返回另外一種類型;不一樣在於let有入參,而run沒有。
  • also/apply。 這倆個函數返回值都是自己,其中apply沒有入參,而also有。

不過即便沒有入參,也能夠經過this,獲得自己。

上述函數的做用仍是挺方便的,好比:

Model model ;
// ...省略初始化過程
if(model!=null){
	// 省略大段的操做邏輯
}
複製代碼

這種寫法,在kotlin中能夠這麼寫:

model?.alse{
	// 省略大段的操做邏輯
}
// 有需求咱們能夠繼續調用它的做用域函數
複製代碼

若是你還有一些else操做,那麼沒轍了,kotlin中也只能老老實實if-else

固然,還有一些有趣的做用域函數,好比在Java中:

boolean isTure;
// 省略boolean判斷邏輯
if(isTure){
	// 省略大段的操做邏輯
}
複製代碼

到Kotlin中能夠這樣來搞:

某對象.takeIf{
	// boolean判斷邏輯
}?.{
	// 省略大段的操做邏輯
}
// 有需求咱們能夠繼續調用它的做用域函數
複製代碼

takeIf:會根據入參的函數的返回值(true/false),決定本身(takeIf)的返回值是null仍是調用者。若是是false,那麼就會返回null,所以這裏使用?的方式繼續去調用後續操做。 我我的比較喜歡做用域函數, 由於能夠省略不少if。接下來咱們來換個稍稍複雜的邏輯:已知一個方法,入參是一個Model,咱們要判斷當這個Model對象的age屬性大於10,打印這個Model對象的名字。 對於Java來講,咱們可能這麼寫:

public void fun(Model model) {
	// 寫了3個if。
    if (model != null) {
        if (model.age>10){
            if (model.name!=null){
                // 打印model.name
            }
        }
    }
}
    
class Model {
    String name;
    int age;
}
複製代碼

對於Kotlin來講,咱們能夠這麼寫:

fun funtion(model : Model){
	model?.takeIf{
		it.age > 10
	}?.let{
		// 打印it.name
	}
}
複製代碼

是否是簡潔了不少?可是單說簡潔這種東西,彷佛並無什麼卵用...不過寫起來,真的很爽!不信,你們能夠試試~~

尾聲

這篇文章,想聊的內容就這麼多。我的認爲其實理解了高階函數,(PS:不知道爲啥起了個名叫高階函數,整得好像很高級似的。)Kotlin就能夠很快的上手,而且能感覺到Kotlin寫起來的爽快之處~ 這裏的確有些安利的意味。那是由於本身最開始對新技術其實接受度並不高,總認爲新東西有各類各樣的問題...當本身去了頭條以後,才發現身邊的同事那種高昂的學習勁頭,(Kotlin?對他們來講不叫新東西...Jatpack,Flutter都已經在線上項目中跑了)本身還有什麼理由說:求求別更新了,我學不動了... 仍是那句話:幹就完了!

我是一個應屆生,最近和朋友們維護了一個公衆號,內容是咱們在從應屆生過渡到開發這一路所踩過的坑,以及咱們一步步學習的記錄,若是感興趣的朋友能夠關注一下,一同加油~

我的公衆號:IT面試填坑小分隊
相關文章
相關標籤/搜索