Kotlin應用於項目踩過的坑

CSDN地址:blog.csdn.net/sinat_36668…java

在谷歌宣佈Kotlin成爲一級開發語言的時候就開始學習kotlin,如今已經在項目中開發使用了。我目前負責的項目老代碼全是java,我不可能全轉成kotlin,因此即使使用了kotlin,也只是在新建文件的代碼裏使用,老代碼繼續用java。kotlin的好處就是徹底兼容java,java調用kotlin,kotlin基本上無阻礙。官網的話就是java和kotlin 100%兼容。git

爲何使用Kotlin

爲何我要改用Kotlin,這是在一個Kotlin社區裏看到的,我以爲他說的比我說的好。Kotlin簡歷,語法簡單,空安全,性能突出,與Java交互性好什麼的。這寫都不是主要的,最重要的是你們都在學Kotlin,感受不寫寫就要落伍了。思考再三,索性直接應用到項目中。github

怎麼使用Kotlin

Kotlin在Android Studio下的初次使用 這篇是我以前本身寫的,我也是按照這個順序來集成的,說明一下,如今的最新版本是 v1.1.3-2。若是有須要你們能夠本身查最新版本傳送門 。尚未在Android Studio中集成Kotlin的能夠先看這個。安全

項目中踩過的坑

1. Kotlin沒有配置直接使用

第一次建立Kotlin Activity,會提示 Kotlin not configured,咱們直接點configure,如圖:bash

這裏寫圖片描述
這裏寫圖片描述

而後點 Android with Gradle dom

這裏寫圖片描述
這裏寫圖片描述

以後進入Kotlin配置界面,默認點 ok 便可ide

這裏寫圖片描述
這裏寫圖片描述

這樣也就配置完成了。這裏我沒有按照這個思路方法實現。我以爲這種方即是方便,可是會有種把本身性命交在其餘人手上的感受。配置好以後點擊sync同步一下就OK了。
圖片來自blog.csdn.net/u010675012/…函數

2. 集合List不能addAll()

在下拉刷新的時候,我將新得來的數據添加到以前的數據集合中,可是addAll()不讓用,最終查資料才知道是由於List集合中沒有這個方法,Are you kidding me???性能

原來在Kotlin中,明確的區分了可變和只讀的集合(list, set, map等),明確的肯定了集合的可讀性,有助於良好的編碼,以及便於Bug的規避。學習

MutableList:

MutableList 接口繼承於List ,MutableCollection&ltE>,是對只讀集合的擴展,增長了了對集合的添加及刪除元素的操做。直接上代碼

private var testList: List<Int>? = null
private fun testList(){
    ...
    testList.addAll(Int)  // 這裏addAll是爆紅,沒有這個方法的
    ...
}複製代碼

修改:

private var testList: MutableList<Int>? = null
private fun testList(){
    ...
    testList.addAll(Int)  // 這樣就解決了這個問題
    ...
}複製代碼

可是在交流過程當中發現這樣也但是實現

private var mList : ArrayList<String> = ArrayList()
    fun testAdd(){
        mList.addAll(mList1)  
        // 這裏也不報錯,這是Kotlin使用Java的ArrayList,交互良好因而可知。不建議這麼用
    }複製代碼

還有一個是arrayListOf(),這個也能實現

private var mList = arrayListOf<Int>()
    fun testget(position:Int){
        mList.add(1)
    }複製代碼

這是爲何呢?我們一點一點的看,先看下MutableList的源碼:

/**
 * A generic ordered collection of elements that supports adding and removing elements.
 * @param E the type of elements contained in the list. The mutable list is invariant on its element type.
 */
public interface MutableList<E> : List<E>, MutableCollection<E> {
    // Modification Operations
    override fun add(element: E): Boolean

    override fun remove(element: E): Boolean

    // Bulk Modification Operations
    override fun addAll(elements: Collection<E>): Boolean

    /**
     * Inserts all of the elements in the specified collection [elements] into this list at the specified [index].
     *
     * @return `true` if the list was changed as the result of the operation.
     */
    public fun addAll(index: Int, elements: Collection<E>): Boolean

    override fun removeAll(elements: Collection<E>): Boolean
    override fun retainAll(elements: Collection<E>): Boolean
    override fun clear(): Unit

    // Positional Access Operations
    /**
     * Replaces the element at the specified position in this list with the specified element.
     *
     * @return the element previously at the specified position.
     */
    public operator fun set(index: Int, element: E): E

    /**
     * Inserts an element into the list at the specified [index].
     */
    public fun add(index: Int, element: E): Unit

    /**
     * Removes an element at the specified [index] from the list.
     *
     * @return the element that has been removed.
     */
    public fun removeAt(index: Int): E

    // List Iterators
    override fun listIterator(): MutableListIterator<E>

    override fun listIterator(index: Int): MutableListIterator<E>

    // View
    override fun subList(fromIndex: Int, toIndex: Int): MutableList<E>
}複製代碼

這裏MutableList繼承了List, MutableCollection,裏面重寫了不少的方法。這裏說的很詳細,我以爲有java基礎的都能看懂,這裏只提供一個思路---看源碼。

再看下arrayListOf的源碼:

/** Returns an empty new [ArrayList]. */
@SinceKotlin("1.1")
@kotlin.internal.InlineOnly
public inline fun <T> arrayListOf(): ArrayList<T> = ArrayList()複製代碼

這裏使用 inline 內聯函數Java中的ArrayList()函數,就是目標代碼的增長爲代價來換取時間的節省。內聯函數又是什麼呢?爲何會有內聯函數呢?

調用某個函數實際上將程序執行順序轉移到該函數所存放在內存中某個地址,將函數的程序內容執行完後,再返回到轉去執行該函數前的地方。這種轉移操做要求在轉去前要保護現場並記憶執行的地址,轉回後先要恢復現場,並按原來保存地址繼續執行。也就是一般說的壓棧和出棧。所以,函數調用要有必定的時間和空間方面的開銷。那麼對於那些函數體代碼不是很大,又頻繁調用的函數來講,這個時間和空間的消耗會很大。

那怎麼解決這個性能消耗問題呢,這個時候須要引入內聯函數了。內聯函數就是在程序編譯時,編譯器將程序中出現的內聯函數的調用表達式用內聯函數的函數體來直接進行替換。顯然,這樣就不會產生轉去轉回的問題,可是因爲在編譯時將函數體中的代碼被替代到程序中,所以會增長目標程序代碼量,進而增長空間開銷,而在時間代銷上不象函數調用時那麼大,可見它是以目標代碼的增長爲代價來換取時間的節省。

listOf

listOf()是使用ArrayList實現的,返回的list是隻讀的,其內存效率更高。在開發過程當中,能夠儘量的多用只讀List,能夠在必定程度上提升內存效率。

private var mList = listOf<Int>()
    fun testget(position:Int){
        mList.get(position)
    }複製代碼

已經成爲源碼狂魔的你確定還想再看listOf()的源碼:

/** Returns an empty read-only list.  The returned list is serializable (JVM). */
@kotlin.internal.InlineOnly
public inline fun <T> listOf(): List<T> = emptyList()複製代碼

看註釋很明白,這裏返回一個只讀的空集合且實現了序列化。我們接着看emptyList()的源碼:

/** Returns an empty read-only list.  The returned list is serializable (JVM). */
public fun <T> emptyList(): List<T> = EmptyList複製代碼

這就已經浮出水面了,emptyList()是List類型。我們接着看EmptyList的源碼:

internal object EmptyList : List<Nothing>, Serializable, RandomAccess {
    private const val serialVersionUID: Long = -7390468764508069838L

    override fun equals(other: Any?): Boolean = other is List<*> && other.isEmpty()
    override fun hashCode(): Int = 1
    override fun toString(): String = "[]"

    override val size: Int get() = 0
    override fun isEmpty(): Boolean = true
    override fun contains(element: Nothing): Boolean = false
    override fun containsAll(elements: Collection<Nothing>): Boolean = elements.isEmpty()

    override fun get(index: Int): Nothing = throw IndexOutOfBoundsException("Empty list doesn't contain element at index $index.")
    override fun indexOf(element: Nothing): Int = -1
    override fun lastIndexOf(element: Nothing): Int = -1

    override fun iterator(): Iterator<Nothing> = EmptyIterator
    override fun listIterator(): ListIterator<Nothing> = EmptyIterator
    override fun listIterator(index: Int): ListIterator<Nothing> {
        if (index != 0) throw IndexOutOfBoundsException("Index: $index")
        return EmptyIterator
    }

    override fun subList(fromIndex: Int, toIndex: Int): List<Nothing> {
        if (fromIndex == 0 && toIndex == 0) return this
        throw IndexOutOfBoundsException("fromIndex: $fromIndex, toIndex: $toIndex")
    }

    private fun readResolve(): Any = EmptyList
}複製代碼

到這裏咱們就看出來了ListOf()中全部的方法。

3. 運算符號報錯

這裏寫圖片描述
這裏寫圖片描述

這裏 - 報錯,這怎麼會出錯?對於剛用於項目中的我也是一臉懵逼。原來使Kotlin的非空機制致使的。由於你的mList?.size加了一個問號因此有可能返回null

private var mList: MutableList<String>? = null
    fun testget(): Int {
        mList?.add("這是第一個:" + 1)
        mList?.add("這是第二個:" + 2)
        return mList?.size - 1   // 報錯
    }複製代碼

怎麼處理這個呢,很簡單,直接加上!!,注意是兩個

private var mList: MutableList<String>? = null
    fun testget(): Int {
        mList?.add("這是第一個:" + 1)
        mList?.add("這是第二個:" + 2)
        return mList?.size!! - 1   // 經過
    }複製代碼

爲何呢?!!操做符,拋出一個非空的B 或者空KNPE(KotlinNullPointerException)。

這裏會拋出KotlinNullPointerException這個異常。由於我們的mList是null。有人說這麼多操做符看着彆扭,怎麼才能不那麼多的操做符呢?

// 從上面知道,這種方式簡單粗暴
    private var mList = arrayListOf<String>()
    fun testget(): Int {
        mList.add("這是第一個:" + 1)
        mList.add("這是第二個:" + 2)
        return mList.size - 1
    }複製代碼

其餘的還須要小夥伴們本身發掘。

因爲篇幅關係只能先到這了,有錯誤的地方歡迎留言指正。

CSDN地址:blog.csdn.net/sinat_36668…
掘金主頁:juejin.im/user/582991…

Kotlin社區交流羣:302755325

這裏寫圖片描述
這裏寫圖片描述
相關文章
相關標籤/搜索