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

这里写图片描述
这里写图片描述
相关文章
相关标签/搜索