[1] —— 在項(xiàng)目中集成并使用Kotlin 與空安全- 初識

這是一個新文集,專門用于記錄學(xué)習(xí) Kotlin 時遇到的一些問題或者心得體會。由于個人水平有限,文章難免會有錯誤之處,望大佬不吝指教。

Kotlin 由來已久,在17年被谷歌納為了 Android 開發(fā)的一級語言,相必大家也多少有些許了解。在開發(fā)工作中,還沒能正式的將項(xiàng)目來使用 Kotlin 開發(fā),但是了解 Kotlin 顯然已是迫在眉睫了。

舊項(xiàng)目引入 Kotlin 開發(fā)

如果你原來的項(xiàng)目使用 Java 編寫的,可以完全放心,我們可以從現(xiàn)在開始每一個新文件都使用 Kotlin 來編寫,Kotlin 與 Java 是百分百的可互相操作的。我們完全可以在保持原項(xiàng)目結(jié)構(gòu)不便的情況下,來使用 Kotlin 進(jìn)行后續(xù)的開發(fā)。

1 引入 Kotlin

  1. 在項(xiàng)目級 build.gradle 文件中引入
buildscript {
    ext.kotlin_version = '1.2.41'
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
  1. 在模塊級 build.gradle 文件中引入
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
  1. 同步項(xiàng)目,開始使用 Kotlin 開始開發(fā)

此時你新建一個 Activity 的話,AS 將提示你可以選擇使用 Kotlin 來進(jìn)行開發(fā);


新建Activity

2 開始開發(fā)

打開我們剛剛新建的這個 Activity,我們來看看 Kotlin 新建的頁面與 Java 文件有那些區(qū)別;

class TestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
    }
}

在 Kotlin 中申明類也是使用關(guān)鍵字 “class”,類之間的繼承使用 “:” ,注意如果被繼承的父類也是一個 Kotlin 類文件(.kt),那么這個父類必須要使用 open 關(guān)鍵字修飾。在 Kotlin 中類默認(rèn)狀況相當(dāng)于在 Java 中使用 final 修飾。

另外 Kotlin 支持 override 父類的成員變量,在父類中使用 open 關(guān)鍵字修飾的成員變量,在子類中可以使用 override 來重寫,這一點(diǎn)在 Java 中是不支持的。

由于我們在前面引入了 apply plugin: 'kotlin-android-extensions' ,這使得我們可以直接在 Activity 中使用控件的 id 來調(diào)用控件,而無需在采用聲明 - findViewById這種方式來實(shí)例化空間了。

例如我們在 xml 文件中放一個 TextView 控件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/mTvText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="這是一個測試的文字"
        android:textColor="#ff00ff"
        android:textSize="18sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

我們可以這樣在 Activity 中操作:

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_test)
        var oldText = mTvText.text
        var newText = "這是一個新的字符串"
        mTvText.text=newText
    }

上述代碼中,我們可以把 text 直接看成是 TextView 的一個公開的成員變量來使用,省去了 get/set 方法,這樣的例子在 Kotlin 中還有很多。

在 Kotlin 中,我們使用 var 來聲明一個可以讀寫的變量,使用 val 來聲明一個只讀變量。使用 val 聲明的變量,在初始化其值后不允許再次賦值。與 Java 不同的是,在 Kotlin 中申明一個變量不一定需要顯示聲明,Kotlin 可以自動的推斷出一個變量的類型,一個變量在類型確定之后不可以修改其類型。

var a: String = ""  //顯示聲明 a 為 String 類型
var b=1                //自動推斷出 b 為 int

空安全

Kotlin 是默認(rèn)空安全的,除非在變量在聲明時使用 “?” 來標(biāo)注該變量可以為 null,否則所有變量默認(rèn)都是不可為 null,這樣可以最大程度的避免空指針異常。

var nullString: String? = null

通常我們在 Android 編程時,都會在類中事先聲明大量的變量,這些變量并不是都能在聲明時初始化,往往很多都是在 Activity 的聲明周期里完成的初始化。

但是在 Kotlin 中 你會發(fā)現(xiàn)有這種情況:


屬性必須初始化或者是抽象的

面對這種情況有兩種解決方法:

  1. init 代碼塊中初始化
var d:String
init {
    d = "init"
}
  1. 使用 lateinitlazy 進(jìn)行延時初始化
    lateinit 用于 var 變量,lazy 用于 val 只讀變量。
    lateinit 延時初始化

空判斷

如果我們已經(jīng)顯式的聲明了一個變量可以為 null,那么在對這個變量進(jìn)行操作時,我們需要對改變了進(jìn)行空判斷,這一點(diǎn) Java 中也是一樣的。

這樣寫在 Java 中是可以通過的,但是 Kotlin 中不可以

Java 中允許這樣書寫代碼

顯而易見的,如果是 Java 代碼,運(yùn)行到此處的時候回報(bào)空指針異常,導(dǎo)致程序崩潰。

在Kotlin 中我們有多種方式來進(jìn)行空判斷:

  1. 傳統(tǒng)的 Java 式在條件中顯示檢查 null
fun print(){
        var nullString: String? = null
        if (nullString != null) {
            println(nullString.length)
        } else {
            println("empty")
        }
    }
  1. 使用安全調(diào)用 “?.” 操作符
    ?. 安全調(diào)用操作符

    使用該操作符時,如果對象為 null,則不會調(diào)用該對象的方法,并且返回 null,不為 null 則正常執(zhí)行
    相當(dāng)于:
if(nullString == null){
    return null
}else{
    return nullString.lenght
}
  1. Elvis 貓王操作符 “?:
    當(dāng)我們有一個可空的引用 r 時,我們可以說“如果 r 非空,我使用它;否則使用某個非空的值 x”,如下(注意:這是 kotlin 特有的操作,相當(dāng)于 Java 中的三元操作符,但是 Kotlin 更為強(qiáng)大允許將 if - else 語句塊中最后一句當(dāng)成返回值返回):
val l: Int = if (b != null) b.length else -1

我們可以將它簡化為:

val l = b?.length ?: -1
Elvis 操作符

可以看出,變量 b 直到運(yùn)算的一刻才轉(zhuǎn)型成字符型,這一操作在 Java 中是不可以的。需要注意的是,如果一個對象被聲明為可能為空,那么除非是采取方法1在條件中判斷 null,否則我們必須采用安全調(diào)用的方式。

4.使用 “!!” 運(yùn)算符
上述的幾種方式都是讓我們?nèi)绾伪苊饪罩羔槷惓#袝r我們需要在代碼里拋出這個異常,這一操作需求在 Java 里是不需要的,因?yàn)橹灰覀儧]有做空判斷,代碼執(zhí)行到此處如果對象為空,必然會 NPE (NullPointerException)。但是在 Kotlin 里一個被聲明為可空的變量是不能直接被調(diào)用的(見上文),這時我們就需要 “!!” 操作符,這個操作符可以使編譯器忽略此處的空檢查,當(dāng)對象為空時,運(yùn)行到此處會 NPE。

!! 操作符拋出 NPE

上述的四種方法就是我們在 Kotlin 中最常用的四種空判斷方式,下面我們來總結(jié)一下:

  • 當(dāng)我們需要一個常規(guī)的空判斷時,使用方法1;
  • 當(dāng)我們需要在對象為空時,表達(dá)式結(jié)果為空,使用方法2;
  • 當(dāng)我們需要在對象為空時,返回另一個表達(dá)式或者值,使用方法3;
  • 當(dāng)我們需要在對象為空時能正常的拋出 NPE,使用方法4;

最后給大家看一個在 Kotlin 中才能使用的騷操作

安全調(diào)用 、Elvis 操作符、if 表達(dá)式

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

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

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