关闭

Kotlin应用于项目踩过的坑

标签: kotlin坑ListOf源码kotlinkotlin配置
1758人阅读 评论(0) 收藏 举报
分类:

CSDN地址:http://blog.csdn.net/sinat_36668731/article/details/77007649

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

Kotlin社区交流群:302755325

这里写图片描述

1
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

Kotlin踩坑笔记

Kotlin踩坑1.kotlin和DataBinding如果直接和Java中一样,只在Gradle中开启databinding编译会报错。解决方法:1.在app的Gradle的开头中加入:apply ...
  • m18826235461
  • m18826235461
  • 2017-09-13 10:52
  • 180

Kotlin应用于项目踩过的坑

在谷歌宣布Kotlin成为一级开发语言的时候就开始学习kotlin,现在已经在项目中开发使用了。我目前负责的项目老代码全是java,我不可能全转成kotlin,所以即便使用了kotlin,也只是在新建...
  • sinat_36668731
  • sinat_36668731
  • 2017-08-09 17:45
  • 1758

那些年在WebView上踩过的坑

之前我在Android中使用WebView与JS交互全解析一文中,介绍了通过Webview和JS的交互方式,但Webview这个控件简直是让人又爱又恨,各种你想不到的错误在各种奇怪的手机上,各种不一样...
  • u012124438
  • u012124438
  • 2016-11-29 23:12
  • 5954

Kotlin最简单的入门教程——集合

集合Kotlin 区分可变集合和不可变集合(lists、sets、maps 等)Kotlin 的 List 类型是一个提供只读操作如 size、get等的接口。和 Java 类似,它继承自 Colle...
  • handongyu2011
  • handongyu2011
  • 2017-06-15 10:47
  • 1364

Mondrian应用于web项目

  • 2013-02-19 14:12
  • 1.10MB
  • 下载

Mondrian应用于web项目

  • 2014-06-05 09:37
  • 1.10MB
  • 下载

Python 多线程多进程10.4.1 应用于自动化测试项目

分布式和并行是完全不同的概念,分布式只负责将一个测试脚本可调用不同的远程环境来执行;并行强调“同时”的概念,它可以借助多线程或多进程技术并行来执行脚本技术。 10.1 单进程的时代 ...
  • qq_26228241
  • qq_26228241
  • 2017-05-20 10:44
  • 237

C++第7周项目1 - 静态成员应用于时间类

课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565,本周题目链接:http://blog.csdn.net/sxhelijia...
  • sxhelijian
  • sxhelijian
  • 2013-04-13 08:27
  • 2450

项目11-随机函数应用于游戏

01./* 02. *Copyright (c) 2016,烟台大学计算机与控制工程学院 03. *All rights reserved. 04. *文件名称:aaa.cpp 05....
  • qccsdn
  • qccsdn
  • 2016-03-24 08:02
  • 344

第4周项目3:随机数函数应用于游戏-猜数字游戏

/* * Copyright(c)2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名称:第4周项目3:随机数函数应用于游戏-猜数字游戏 * 作者:...
  • CiMaoShuShu
  • CiMaoShuShu
  • 2016-03-23 19:35
  • 136
    个人资料
    • 访问:34502次
    • 积分:1072
    • 等级:
    • 排名:千里之外
    • 原创:65篇
    • 转载:1篇
    • 译文:0篇
    • 评论:25条
    最新评论