JVM中性能更好的ArrayList<Int>

20 篇文章 1 订阅
6 篇文章 0 订阅

前言

众所周知,kotlin中有ArrayList<Int>,Array<Int>,IntArray,可他们都有什么区别呢?为什么要有这么多大致相同的类型?

正文

我们先看一下他们相对于jvm中的类型

ArrayList<Int> = ArrayList<Integer>

Array<Int> = Integer[]

IntArray = int[]

可以看出来前面两种都用到了int的包装类型Integer,而IntArray是用的基础数据类型int,在下面这篇文章中看到,由于jvm的自动装箱和拆箱导致包装类型性能更差(时间和空间上).[Kotlin的基本数值类型问题:是对象?还是基本数据类型?]

但是ArrayList<Int>是有可变的数量上限的(扩容机制),而IntArray并没有,如果我们想要一个可以扩容的IntArray,而且也使用基础数据类型(性能更好)时,怎么办呢?我们可以仿照ArrayList<Int>写一个基本数据类型的,如下代码:

ps:项目已开源: ltttttttttttt/DataStructure: (常用的自定义的数据结构) (github.com)

package com.lt.androidkj.utils.collection

/**
 * creator: lt  2021/11/10  lt.dygzs@qq.com
 * effect : 性能更好的ArrayList<Int>,线程不安全
 * warning:[initSize]初始化容量
 */
class IntArrayList(initSize: Int = 10) : RandomAccess {
    constructor(intArray: IntArray) : this(intArray.size) {
        data = intArray.copyOf()
        size = data.size
    }

    constructor(intArrayList: IntArrayList) : this(intArrayList.data.copyOf(intArrayList.size))

    constructor(list: Collection<Int>) : this(list.size) {
        list.forEach(::add)
    }

    //内部数据
    private var data: IntArray = IntArray(initSize) { 0 }

    /**
     * 获取内部的总数量
     */
    var size: Int = 0
        private set

    /**
     * 获取数据
     */
    operator fun get(index: Int): Int {
        if (index >= size)
            throw IndexOutOfBoundsException("size = $size ,the index = $index")
        return data[index]
    }

    /**
     * 获取数据,如果索引越界,就返回else的返回值
     */
    inline fun getOrElse(index: Int, defaultValue: () -> Int): Int {
        if (index !in 0 until size)
            return defaultValue()
        return get(index)
    }

    /**
     * 获取数据,如果索引越界,就返回null
     */
    fun getOrNull(index: Int): Int? {
        if (index !in 0 until size)
            return null
        return get(index)
    }

    /**
     * 添加数据
     * 扩容机制:容量翻倍
     */
    fun add(element: Int) {
        if (size == data.size)
            data = data.copyOf(data.size * 2)
        data[size] = element
        size++
    }

    /**
     * 根据数据移除
     */
    fun removeElement(element: Int) {
        val indexOf = indexOf(element)
        if (indexOf >= 0) {
            removeAtIndex(indexOf)
        }
    }

    /**
     * 根据索引移除
     */
    fun removeAtIndex(index: Int) {
        if (index >= size)
            throw IndexOutOfBoundsException("size = $size ,the index = $index")
        val numMoved = size - index - 1
        if (numMoved > 0)
            System.arraycopy(data, index + 1, data, index, numMoved)
        size--
    }

    /**
     * 移除第一个位置
     */
    fun removeFirst() = removeAtIndex(0)

    /**
     * 移除最后一个位置
     */
    fun removeLast() = removeAtIndex(size - 1)

    /**
     * 设置某个索引的数据
     */
    operator fun set(index: Int, element: Int): Int {
        if (index >= size)
            throw IndexOutOfBoundsException("size = $size ,the index = $index")
        val oldElement = get(index)
        data[index] = element
        return oldElement
    }

    /**
     * 如果[index]没有超过size就设置,否则丢弃该次修改
     */
    fun setOrDiscard(index: Int, element: Int) {
        if (index >= size || index < 0) return
        set(index, element)
    }

    /**
     * 获取内部是否没有数据
     */
    fun isEmpty(): Boolean = size == 0

    /**
     * 获取对应数据的索引,如果没有则返回-1
     */
    fun indexOf(element: Int): Int {
        forEachIndexed { index, datum ->
            if (element == datum)
                return index
        }
        return -1
    }

    /**
     * 从后往前获取对应数据的索引,如果没有则返回-1
     */
    fun lastIndexOf(element: Int): Int {
        forEachReversedIndexed { index, datum ->
            if (element == datum)
                return index
        }
        return -1
    }

    /**
     * 获取是否存在对应数据
     */
    operator fun contains(element: Int): Boolean = indexOf(element) >= 0

    /**
     * 获取迭代器
     */
    operator fun iterator(): MutableIterator<Int> = object : MutableIterator<Int> {
        private var index = 0
        override fun hasNext(): Boolean = size > index
        override fun next(): Int = get(index++)
        override fun remove() = removeAtIndex(--index)
    }

    /**
     * 遍历的方法
     * ps:使用forEach系列比for性能好(因为迭代器的next()返回的是对象)
     */
    inline fun forEach(action: (element: Int) -> Unit) {
        forEachIndexed { _, element -> action(element) }
    }

    inline fun forEachIndexed(action: (index: Int, element: Int) -> Unit) {
        var index = 0
        while (index < size) {
            action(index, get(index))
            index++
        }
    }

    /**
     * 倒序遍历
     */
    inline fun forEachReversedIndexed(action: (index: Int, element: Int) -> Unit) {
        var index = size - 1
        while (index >= 0) {
            action(index, get(index))
            index--
        }
    }

    /**
     * 获取一段IntArrayList
     */
    fun subList(fromIndex: Int, toIndex: Int): IntArrayList {
        if (toIndex > size)
            throw IndexOutOfBoundsException("size = $size ,the toIndex = $toIndex")
        return IntArrayList(data.copyOfRange(fromIndex, toIndex))
    }

    /**
     * 安全的subList,索引超限部分不会返回内容
     */
    fun subListWithSafe(fromIndex: Int, toIndex: Int): IntArrayList =
        IntArrayList(data.copyOfRange(maxOf(0, fromIndex), minOf(size, toIndex)))

    /**
     * 批量添加数据
     */
    fun addAll(elements: Collection<Int>) {
        elements.forEach(::add)
    }

    fun addAll(elements: IntArrayList) {
        addAll(elements.data.copyOf(elements.size))
    }

    fun addAll(elements: IntArray) {
        elements.forEach(::add)
    }

    fun addAllNotNull(elements: Collection<Int?>?) {
        elements?.forEach {
            if (it != null)
                add(it)
        }
    }

    /**
     * 批量移除数据
     */
    fun removeAll(elements: Collection<Int>) {
        elements.forEach(::removeElement)
    }

    fun removeAll(elements: IntArrayList) {
        removeAll(elements.data.copyOf(elements.size))
    }

    fun removeAll(elements: IntArray) {
        elements.forEach(::removeElement)
    }

    /**
     * 清空数据
     */
    fun clear() {
        size = 0
    }

    /**
     * 转换数据结构
     */
    fun toIntArray() = data.copyOf(size)

    fun toMutableList() = toIntArray().toMutableList()

    override fun toString(): String {
        return "[" + data.copyOf(size).joinToString(",") + "]"
    }
}

fun intArrayListOf(vararg elements: Int): IntArrayList = IntArrayList(elements)

其性能更好,内部使用基础数据类型,而且支持自动扩容,使用方式基本和ArrayList一样

如果你想装Double的话,只需要copy一份将Int改成Double就可以了

end

对Kotlin或KMP感兴趣的同学可以进Q群 101786950

如果这篇文章对您有帮助的话

可以扫码请我喝瓶饮料或咖啡(如果对什么比较感兴趣可以在备注里写出来)

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"Address already in use: JVM_Bind <null>:8009"是一种错误信息,表示在尝试绑定到指定地址和端口时,该地址和端口已经被其他应用程序使用了。这个错误通常是由于另一个进程正在监听相同的地址和端口引起的。在这种情况下,您需要找到并停止正在使用该地址和端口的进程,或者选择一个不同的地址和端口来绑定。 要解决这个问题,您可以按照以下步骤进行操作: 1. 首先,您可以使用命令行工具(如Windows的命令提示符或Linux的终端)来查找使用指定端口的进程。在命令提示符或终端输入以下命令: - Windows:`netstat -ano | findstr :8009` - Linux:`sudo netstat -tulpn | grep :8009` 2. 运行上述命令后,您将看到正在使用端口8009的进程的详细信息,包括进程ID(PID)。 - 在Windows,PID位于最后一列。 - 在Linux,PID位于第二列(可能是在`LISTEN`或`ESTABLISHED`状态下)。 3. 使用以下命令来终止使用指定PID的进程: - Windows:`taskkill /PID <PID>` - Linux:`sudo kill <PID>` 4. 终止进程后,您可以重新尝试绑定到地址和端口8009,这应该不再出现"Address already in use: JVM_Bind <null>:8009"的错误信息了。 请注意,如果您终止了一个正在运行的进程,这可能会导致该进程的异常关闭。因此,请确保您了解被终止的进程对系统的影响,并在终止之前保存任何重要的数据。 这些步骤可以帮助您解决"Address already in use: JVM_Bind <null>:8009"的问题,使您能够成功绑定到指定的地址和端口。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Address already in use: JVM_Bind 问题](https://blog.csdn.net/M_123hj_520/article/details/47724689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值