Kotlin基礎:白話文轉文言文般的Kotlin常識

這是該系列的第一篇,系列文章目錄以下:java

  1. Kotlin基礎:白話文轉文言文般的Kotlin常識spring

  2. Kotlin基礎:望文生義的Kotlin集合操做編程

  3. Kotlin實戰:用實戰代碼更深刻地理解預約義擴展函數安全

  4. Kotlin實戰:使用DSL構建結構化API去掉冗餘的接口方法bash

  5. Kotlin基礎:屬性也能夠是抽象的app

  6. Kotlin進階:動畫代碼太醜,用DSL動畫庫拯救,像說話同樣寫代碼喲!ide

  7. Kotlin基礎:用約定簡化相親函數

這個系列記錄的是kotlin使用感覺,其中也會穿插基礎知識點,並經過項目實戰代碼綜合運用這些知識點。工具

剛接觸kotlin就被它的簡潔震撼到了(kotlin的做者必定是一個極簡主義!)。一塊兒來看下kotlin是怎麼經過「斷舍離」來實現簡潔的:post

new 分號 類型

新建對象不須要new關鍵詞。

任何語句的結尾不須要; 但加上也不會有語法錯誤。

//java
StringBuffer buffer = new StringBuffer();

//kotlin
var buffer = StringBuffer()
複製代碼
  • varkotlin保留字,用於聲明變量。與之對應的是val用於聲明常量,常量意思是引用不可變,但並不表明其引用對象也不可變。
  • 不須要顯示指明變量類型,由於kotlin會根據上下文推斷變量類型,這種能力稱爲 「類型推導」
  • 能夠經過下面的語法來指定類型:
var buffer: StringBuffer = StringBuffer()
複製代碼
  • kotlin中類型是後置的,在變量名後跟上: 類型就能夠顯示指定類型。同理,它也用於指定函數返回值類型:
fun getMessage(): String{
    return "message"
}
複製代碼
  • fun關鍵字用於聲明函數。

implements extends @Override

//java
public class CheckableActivity extends Activity {
    final public void setStatus(){}
}

public class MyListener implements View.OnClickListener{

    @Override
    public void onClick(View v) {
    }
}

//kotlin
class CirclePartyListActivity : Activity() {
    fun setStatus(){}
}

class MyListener : View.OnClickListener{
    override fun onClick(v: View?) {
    }
}
複製代碼
  • kotlin: 取代了implementsextends保留字。

  • @Override也被override保留字取代而且和函數頭同行,kotlin中的override是必須的,而java中是可選的。

  • kotlin中類和方法默認是final的(可省略不寫),這意味着默認狀況下,類和方法是不容許被繼承和重寫的(這是爲了防止脆弱的基類,即對基類方法的修改會致使子類出現預期以外的行爲)。只有經過open保留字顯示聲明該類或方法能夠被繼承或重寫:

open class A{
    open fun do(){
    }
}
複製代碼

()

kotlinlambda也更加簡約:

//正常狀況
view.setOnClickListener({ v -> v.setVisibility(View.INVISIBLE) })
//當lambda是函數的最後一個參數時,能夠將其移到括號外面
view.setOnClickListener() { v -> v.setVisibility(View.INVISIBLE) }
//當函數只有一個lambda類型的參數,能夠去省去括號
view.setOnClickListener { v -> v.setVisibility(View.INVISIBLE) }
//當lambda只有一個參數,可省去參數列表,在表達式部分用it引用參數
view.setOnClickListener { it.setVisibility(View.INVISIBLE) }
複製代碼

getter setter

java中,字段和其訪問器的組合被稱爲屬性,kotlin引入了property access syntax,它取代了字段和訪問器方法,用這種方式進一步簡化上面的代碼:

view.setOnClickListener { it.visibility = View.INVISIBLE }
複製代碼
  • 全部被定義了gettersetter方法的字段,在kotlin中均可以經過賦值語法來操做。

{ } return

kotlin中的語句和表達式的惟一區別是:表達式有值,而語句沒有。若是函數體由單個表達式構成,能夠省去花括號和return,並用賦值的=表示將表達式的值賦值給返回值,這種語法叫表達式函數體

//java
public int add(int a, int b){
    return a+b ;
}

//kotlin
fun add(a: Int, b: Int): Int = a+b
複製代碼

在 lambda 表達式中包含多條語句或表達式時,若省略return,則默認將最後一個表達式的值做爲返回值:

view.setOnTouchListener { v, event ->
    ...//do something
    false
}
複製代碼

上述代碼表示在OnTouchListener.onTouch()中返回 false。

switch-case-break

//java
String color;
switch(colorInt){
    case Color.RED:
        color = "red";
        break;
    case Color.BLUE:
        color = "blue";
        break;
    default:
        color = "black";
        break;
}

//kotlin
val color = when (colorInt) {
    Color.RED -> "red"
    Color.BLUE -> "blue"
    else -> "black"
}
複製代碼
  • when用於取代switch-case,不須要在每一個分支末尾調用break,若是有一個分支命中則會當即返回。
  • when是一個表達式,這意味着它有返回值,返回值等於命中分支中最後一條語句的返回值。

default

java中的default保留字用於接口中默認方法的實現。在kotlin中能夠省去它。

//java
public interface IMessage {
    default String getMessage() {
        return "default message";
    }

    int getMessageId();
}

//kotlin
interface IMessage {
    fun getMessage(): String {
        return "default message"
    }

    fun getMessageId(): Int
}
複製代碼
  • Intjava中基本數據類型int的包裝類,kotlin中沒有基本數據類型。

防護式編程

//java
public class Address {
    private String country;
    public String getCountry() {
        return country;
    }
}

public class Company {
    private Address address;
    public Address getAddress() {
        return address;
    }
}

public class Person {
    private Company company;
    public String getCountry() {
        String country = null;
        //屢次防護式編程
        if (company != null) {
            if (company.getAddress() != null) {
                country = company.getAddress().getCountry();
            }
        }
        return country;
    }
}

//kotlin
fun Person.getCountry(): String? {
    return this.company?.address?.country
}
複製代碼
  • ?.稱爲 安全調用運算符 ,它把判空檢查和一次方法調用合併成一個操做。只有當調用變量不爲null時,纔會執行調用,不然整個表達式返回null。這意味着,再也不須要防護式編程。
  • ?置於類型以後表示這個類型可空,上面的函數聲明表示此函數的返回值可能爲null
  • 上面的 kotlin 代碼爲Person類添加了一個getCountry()方法,這種技術叫擴展函數

擴展函數

擴展函數是一個類的成員函數,但它定義在類體外面。這樣定義的好處是,能夠在任什麼時候候任何地方給類添加功能。

在擴展函數中,能夠像類的其餘成員函數同樣訪問類的屬性和方法(除了被privateprotected修飾的成員)。還能夠經過this引用類的實例,也能夠省略它,把上段代碼進一步簡化:

fun Person.getCountry(): String? {
    return company?.address?.country
}
複製代碼

kotlin預約了不少擴展函數,下面就會用到其中的apply

冗餘對象名

編程中常常會遇到「對同一個對象作屢次操做」的場景,好比:

Intent intent = new Intent(this, Activity1.class);
intent.setAction("actionA");
Bundle bundle = new Bundle();
bundle.putString("content","hello");
bundle.putString("sender","taylor");
intent.putExtras(bundle);
startActivity(intent);
複製代碼

其中,對象intentbundle重複出現若干次,這對於極簡主義的kotlin來講不能忍,它的表達方式以下:

Intent(this,Activity1::class.java).apply {
    action = "actionA"
    putExtras(Bundle().apply {
        putString("content","hello")
        putString("sender","taylor")
    })
    startActivity(this)
}
複製代碼

其中,apply的定義以下:

//爲泛型T對象添加新功能apply(),它接受一個lambda類型的參數block,且lambda調用的發起者是對象自己
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    //執行lambda
    block()
    //返回調用者自身
    return this
}
複製代碼

對於object.apply{lambda}能夠簡單的理解爲:在object對象上應用lambda操做,而且最終返回object對象自己。因此上述代碼也能夠寫成更加緊湊的形式:

startActivity(Intent(this, Activity1::class.java).apply {
    action = "actionA"
    putExtras(Bundle().apply {
        putString("content", "hello")
        putString("sender", "taylor")
    })
})
複製代碼

同一類型的預約義擴展函數還包括withletalso。它們的共同點是適用於 「對同一個對象作屢次操做」 的場景 。它們的不一樣點總結以下:

函數 返回值 調用者角色 如何引用調用者
also 調用者自己 做爲lambda參數 it
apply 調用者自己 做爲lambda接收者 this
let lambda返回值 做爲lambda參數 it
with lambda返回值 做爲lambda接收者 this
  • kotlin中,發起調用擴展函數的那個對象,叫接收者對象。同理,發起調用lambda的對象叫作lambda接收者
  • 能夠將also的源碼和apply作對比,更好的理解他們調用者角色的差異:
//爲泛型T對象添加新功能also(),它接受一個lambda類型的參數block,且對象是lambda的參數
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}
複製代碼

綜合應用

「讓 app 中全部被點擊的 View 都帶上縮放動畫」。綜合運用上述kotlin知識點實現這個需求以前,先來看看java是如何實現的:

  1. 先定義工具類,該工具類爲傳入的View分別設置觸摸和單擊監聽器。在按下時播放動畫,鬆手時反向播放動畫。
public class ViewUtil {
    public static void addExtraAnimClickListener(View view, ValueAnimator animator, View.OnClickListener listener) {
        view.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        animator.start();
                        break;
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP:
                        animator.reverse();
                        break;
                }
                //若返回true,則屏蔽了點擊事件
                return false;
            }
        });

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null) {
                    listener.onClick(v);
                }
            }
        });
    }
}
複製代碼
  1. 在界面中新建動畫和點擊響應邏輯並將它們傳遞給工具類
Button btn3 = findViewById(R.id.btn3);
//新建動畫:變大
ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 1.2f);
animator.setDuration(100);
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float value = ((Float) animation.getAnimatedValue());
        btn3.setScaleX(value);
        btn3.setScaleY(value);
    }
});
//點擊響應邏輯
View.OnClickListener onClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(Activity1.this, "spring anim", Toast.LENGTH_LONG).show();
    }
};
//應用工具類
ViewUtil.addExtraAnimClickListener(btn3, animator, onClickListener);
複製代碼

不要眨眼,換kotlin閃亮登場:

  1. 給View添加擴展函數
//擴展函數接收一個動畫和一個點擊響應邏輯(用lambda表示)
fun View.extraAnimClickListener(animator: ValueAnimator, action: (View) -> Unit) {
    setOnTouchListener { v, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> animator.start()
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> animator.reverse()
        }
        false
    }
    setOnClickListener { action(this) }
}
複製代碼
  1. 應用擴展函數
btnSpringAnim.extraAnimClickListener(ValueAnimator.ofFloat(1.0f, 1.15f).apply {
    interpolator = AccelerateInterpolator()
    duration = 100
    addUpdateListener {
        btnSpringAnim.scaleX = it.animatedValue as Float
        btnSpringAnim.scaleY = it.animatedValue as Float
    }
}) { Toast.makeText(this, "spring anim", Toast.LENGTH_LONG).show() }
複製代碼
  • btnSpringAnim是一個Button控件的id(只要裝了kotlin插件,就不須要findViewById())
  • as保留字用於類型強制轉換。
  • 是否是有一種 「白話文轉文言文」 的感受,kotlin憑藉着極強的表達力用將近 1/3 的代碼量完成了功能。

知識點總結

  • var保留詞用於聲明變量,val保留詞用於聲明常量。大多數狀況下不須要顯示指明變量類型,kotlin 具備類型推導能力,會根據上下文自動推斷類型。
  • fun保留字用於聲明函數。
  • override保留字表示重寫父類方法或者實現接口中的抽象方法,與 java 不一樣的是,它必須顯示出如今重寫方法前( java 容許省略)。
  • as保留字用於類型強制轉換。
  • kotlin 中類型是後置的,在變量名或函數參數列表後跟上: 類型就能夠顯示指定類型。
  • :還用於繼承類(取代extends)、實現接口(取代implements)。
  • 新建對象時不須要new,而是直接調用構造函數。
  • 語句末尾不須要; 但加上也不會有語法錯誤。
  • kotlin 中類和方法默認是final的,他們不能被繼承和重寫。只有經過加上open後才能被繼承和重寫。
  • kotlin 中沒有基本數據類型,而是用其對應的包裝類表示。
  • 給接口方法添加默認實現時不須要default關鍵字。
  • kotlin 中的語句和表達式的惟一區別是:表達式有值,而語句沒有。
  • 若是函數體由單個表達式構成,能夠省去花括號和return。
  • when保留字用於取代switch-case,並且它是一個表達式,返回值是命中分支中最後一表達式的值。
  • kotlin 引入了property access syntax,再也不須要getter和setter方法,能夠直接對屬性賦值。
  • ?.稱爲 安全調用運算符 ,只有當調用變量不爲null時,纔會執行調用,不然整個表達式返回null。這樣就避免了防護式編程。
  • ?置於類型以後表示這個類型的變量或返回值值可能爲null
  • kotlin 使用擴展函數,能夠在類體外給類新增方法。
  • kotlin 預約了不少擴展函數,其中有一類適用於「對同一個對象作屢次操做」。包括also()apply()let()with()

最近開始學習 kotlin ,研讀《Kotlin實戰》的同時,在項目中加以運用。這個系列會不斷地新增來自書本和實踐中的新發現。但願對你能有所幫助~~

相關文章
相關標籤/搜索