Kotlin应用于项目踩过的坑

CSDN地址:http://blog.csdn.net/sinat_36668731/article/details/77007649
掘金地址:https://juejin.im/post/598ada1651882548981919be

在谷歌宣布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了。
图片来自:http://blog.csdn.net/u010675012/article/details/72590946

2. 集合List不能addAll()

在下拉刷新的时候,我将新得来的数据添加到之前的数据集合中,但是addAll()不让用,最终查资料才知道是因为List集合中没有这个方法,Are you kidding me???

原来在Kotlin中,明确的区分了可变和只读的集合(list, set, map等),明确的确定了集合的可读性,有助于良好的编码,以及便于Bug的规避。

MutableList:

MutableList<E>接口继承于List<E>,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地址:http://blog.csdn.net/sinat_36668731?viewmode=list
掘金主页:https://juejin.im/user/582991ff570c3500587d2da9

Kotlin社区交流群:302755325

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容