Kotlin应用于项目踩过的坑

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

在谷歌宣布Kotlin成为一级开发语言的时候就开始学习kotlin,现在已经在项目中开发使用了。我目前负责的项目老代码全是java,我不可能全转成kotlin,所以即便使用了kotlin,也只是在新建文件的代码里使用,老代码继续用java。kotlin的好处就是完全兼容java,java调用kotlin,kotlin基本上无阻碍。官网的话就是java和kotlin 100%兼容。

为什么使用Kotlin

为什么我要改用Kotlin,这是在一个Kotlin社区里看到的,我觉得他说的比我说的好。Kotlin简历,语法简单,空安全,性能突出,与Java交互性好什么的。这写都不是主要的,最重要的是大家都在学Kotlin,感觉不写写就要落伍了。思考再三,索性直接应用到项目中。

怎么使用Kotlin

Kotlin在Android Studio下的初次使用 这篇是我之前自己写的,我也是按照这个顺序来集成的,说明一下,现在的最新版本是 v1.1.3-2。如果有需要大家可以自己查最新版本传送门 。还没有在Android Studio中集成Kotlin的可以先看这个。

项目中踩过的坑

1. Kotlin没有配置直接使用

第一次创建Kotlin Activity,会提示 Kotlin not configured,我们直接点configure,如图:

这里写图片描述

然后点 Android with Gradle

这里写图片描述

之后进入Kotlin配置界面,默认点 ok 即可

这里写图片描述

这样也就配置完成了。这里我没有按照这个思路方法实现。我觉得这种方便是方便,但是会有种把自己性命交在其他人手上的感觉。配置好之后点击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

这里写图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值