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,如图:
Kotlin应用于项目踩过的坑
文章图片
这里写图片描述 然后点 Android with Gradle
Kotlin应用于项目踩过的坑
文章图片
这里写图片描述 之后进入Kotlin配置界面,默认点 ok 即可
Kotlin应用于项目踩过的坑
文章图片
这里写图片描述 这样也就配置完成了。这里我没有按照这个思路方法实现。我觉得这种方便是方便,但是会有种把自己性命交在其他人手上的感觉。配置好之后点击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<E>,是对只读集合的扩展,增加了了对集合的添加及删除元素的操作。直接上代码
private var testList: List? = null private fun testList(){ ... testList.addAll(Int)// 这里addAll是爆红,没有这个方法的 ... }

修改:
private var testList: MutableList? = null private fun testList(){ ... testList.addAll(Int)// 这样就解决了这个问题 ... }

但是在交流过程中发现这样也可是实现
private var mList : ArrayList = ArrayList() fun testAdd(){ mList.addAll(mList1) // 这里也不报错,这是Kotlin使用Java的ArrayList,交互良好由此可见。不建议这么用 }

还有一个是arrayListOf(),这个也能实现
private var mList = arrayListOf() 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 : List, MutableCollection { // Modification Operations override fun add(element: E): Booleanoverride fun remove(element: E): Boolean// Bulk Modification Operations override fun addAll(elements: Collection): 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): Booleanoverride fun removeAll(elements: Collection): Boolean override fun retainAll(elements: Collection): 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(): MutableListIteratoroverride fun listIterator(index: Int): MutableListIterator// View override fun subList(fromIndex: Int, toIndex: Int): MutableList }

这里MutableList继承了List, MutableCollection,里面重写了很多的方法。这里说的很详细,我觉得有java基础的都能看懂,这里只提供一个思路---看源码。
再看下arrayListOf的源码:
/** Returns an empty new [ArrayList]. */ @SinceKotlin("1.1") @kotlin.internal.InlineOnly public inline fun arrayListOf(): ArrayList = ArrayList()

【Kotlin应用于项目踩过的坑】这里使用 inline 内联函数Java中的ArrayList()函数,就是目标代码的增加为代价来换取时间的节省。内联函数又是什么呢?为什么会有内联函数呢?
调用某个函数实际上将程序执行顺序转移到该函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行。也就是通常说的压栈和出栈。因此,函数调用要有一定的时间和空间方面的开销。那么对于那些函数体代码不是很大,又频繁调用的函数来说,这个时间和空间的消耗会很大。
那怎么解决这个性能消耗问题呢,这个时候需要引入内联函数了。内联函数就是在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来直接进行替换。显然,这样就不会产生转去转回的问题,但是由于在编译时将函数体中的代码被替代到程序中,因此会增加目标程序代码量,进而增加空间开销,而在时间代销上不象函数调用时那么大,可见它是以目标代码的增加为代价来换取时间的节省。
listOf listOf()是使用ArrayList实现的,返回的list是只读的,其内存效率更高。在开发过程中,可以尽可能的多用只读List,可以在一定程度上提高内存效率。
private var mList = listOf() 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 listOf(): List = emptyList()

看注释很明白,这里返回一个只读的空集合且实现了序列化。咱们接着看emptyList()的源码:
/** Returns an empty read-only list.The returned list is serializable (JVM). */ public fun emptyList(): List = EmptyList

这就已经浮出水面了,emptyList()是List类型。咱们接着看EmptyList的源码:
internal object EmptyList : List, Serializable, RandomAccess { private const val serialVersionUID: Long = -7390468764508069838Loverride 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): 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 = -1override fun iterator(): Iterator = EmptyIterator override fun listIterator(): ListIterator = EmptyIterator override fun listIterator(index: Int): ListIterator { if (index != 0) throw IndexOutOfBoundsException("Index: $index") return EmptyIterator }override fun subList(fromIndex: Int, toIndex: Int): List { if (fromIndex == 0 && toIndex == 0) return this throw IndexOutOfBoundsException("fromIndex: $fromIndex, toIndex: $toIndex") }private fun readResolve(): Any = EmptyList }

到这里我们就看出来了ListOf()中所有的方法。
3. 运算符号报错
Kotlin应用于项目踩过的坑
文章图片
这里写图片描述 这里 - 报错,这怎么会出错?对于刚用于项目中的我也是一脸懵逼。原来使Kotlin的非空机制导致的。因为你的mList?.size加了一个问号所以有可能返回null
private var mList: MutableList? = null fun testget(): Int { mList?.add("这是第一个:" + 1) mList?.add("这是第二个:" + 2) return mList?.size - 1// 报错 }

怎么处理这个呢,很简单,直接加上!!,注意是两个
private var mList: MutableList? = null fun testget(): Int { mList?.add("这是第一个:" + 1) mList?.add("这是第二个:" + 2) return mList?.size!! - 1// 通过 }

为什么呢?!!操作符,抛出一个非空的B 或者空KNPE(KotlinNullPointerException)。
这里会抛出KotlinNullPointerException这个异常。因为咱们的mList是null。有人说这么多操作符看着别扭,怎么才能不那么多的操作符呢?
// 从上面知道,这种方式简单粗暴 private var mList = arrayListOf() 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

    推荐阅读