LinkedList的一种错误用法

最近在做图像处理的时候,发现某一段代码非常的慢,慢得让人无法接受。主要的代码是顺序访问一个LinkedList的元素,效果是随着index的变大,速度越来越慢,list的元素个数在百万以上。找到原因,分享出来,也希望大家不要跳入同一个陷阱。还是那一句话,可运行的代码和高质量的代码之间还是有比较远的距离。

LinkedList错误用法示例

代码里面加入了一些打印时间相关的代码,主要是为了直观的显示运行的耗时。

错误代码

public static void main(String[] args) {
    // add elements
    int size = 2000000;
    List<String> list = new LinkedList<String>();
    for (int i = 0; i < size; i++) {
        list.add("Just some test data");
    }

    long startTime = System.currentTimeMillis();
    for (int i = 0; i < size; i++) {
        list.get(i);

        if (i % 10000 == 0) {
            System.out.println("query 10000 elements spend: "
                    + (System.currentTimeMillis() - startTime));
            startTime = System.currentTimeMillis();
        }
    }
}

控制台输出如下:

错误原因

错误的代码就是list.get(i),LinkedList的底层是一个链表,随机访问i的时候,链表只能从头往后数,第i个才返回。所以时间随着i的变大时间会越来越长。

正确用法

顺序访问,LinkedList绝对不要用get方法,即使LinkedList的元素个数只有很少的几个。养成好习惯,免得犯错。

for each

for (String element : list) {
    // process element here
}

iterator

Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String element = iter.next();
    // process element here
}

直接换为ArrayList

public static void main(String[] args) {
    // add elements
    int size = 2000000;
    List<String> list = new ArrayList<String>();
    for (int i = 0; i < size; i++) {
        list.add("Just some test data");
    }

    long startTime = System.currentTimeMillis();
    for (int i = 0; i < size; i++) {
        list.get(i);

        if (i % 10000 == 0) {
            System.out.println("query 10000 elements spend: "
                    + (System.currentTimeMillis() - startTime));
            startTime = System.currentTimeMillis();
        }
    }
}

ArrayList的控制台输出如下:

LinkedList VS ArrayList

下面比较一下LinkedList和ArrayList的效率。

新增、查询、删除比较

ArrayList测试代码如下:

public static void main(String[] args) {
    // add elements
    int size = 20000000;
    List<String> list = new ArrayList<String>();
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < size; i++) {
        list.add("Just some test data");
    }
    System.out.println("add " + size + " elements spend: "
            + (System.currentTimeMillis() - startTime));

    // query
    startTime = System.currentTimeMillis();
    String median = list.get(size / 2);
    System.out.println("query median spend: "
            + (System.currentTimeMillis() - startTime));

    // delete
    startTime = System.currentTimeMillis();
    list.remove(median);
    System.out.println("delete median spend: "
            + (System.currentTimeMillis() - startTime));
}

LinkedList测试代码如下:

public static void main(String[] args) {
    // add elements
    int size = 20000000;
    List<String> list = new LinkedList<String>();
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < size; i++) {
        list.add("Just some test data");
    }
    System.out.println("add " + size + " elements spend: "
            + (System.currentTimeMillis() - startTime));

    // query
    startTime = System.currentTimeMillis();
    String median = list.get(size / 2);
    System.out.println("query median spend: "
            + (System.currentTimeMillis() - startTime));

    // delete
    startTime = System.currentTimeMillis();
    list.remove(median);
    System.out.println("delete median spend: "
            + (System.currentTimeMillis() - startTime));
}

各自特点

  • 新增

    ArrayList比LinkedList快很多,超过一个数量级。很是意外。

  • 随机查询

    在i值很大的时候,ArrayList比LinkedList快很多,i越大,差距越大。ArrayList底层是数组,随机访问时间效率是O(0),而LinkedList是O(n)。

  • 删除

    LinkedList比ArrayList快很多。LinkedList的删除操作时间效率为O(0),而ArrayList是O(n),ArrayList需要查找数据、移动数据,所以慢。

总结

尽量使用ArrayList,ArrayList满足不了需求的时候再用LinkedList。根据LinkedList的特点,在下面几种情况下才使用LinkedList。

  • 需要使用java.util.List接口之外的API

    LinkedList实现了Queue和Stack等接口,可以用来当作一些特殊的容器。吐槽JDK里面LinkedList的设计,塞太多东西了,和名字不符。

  • 元素删除比较频繁

    如果数据量大,删除频繁,只能用LinkedList。

  • 内存碎片化且元素很多

    ArrayList底层是一个数组,数组要求一段连续的内存快。LinkedList也可以充分利用内存的一些碎片。特别是JVM使用Concurrent Mark-Sweep Collector垃圾回收器的时候,显得尤为重要。

LinkedList的一种错误用法

时间: 2024-09-29 22:31:32

LinkedList的一种错误用法的相关文章

一直被用错的6种SQL 错误用法

一直被用错的6种SQL 错误用法 1.LIMIT 语句 2.隐式转换 3.关联更新.删除 4.EXISTS语句 5.条件下推 6.提前缩小范围 sql语句的执行顺序: FROM ON JOIN WHERE GROUP BY HAVING SELECTDISTINCT ORDER BY LIMIT 1.LIMIT 语句 分页查询是最常用的场景之一,但也通常也是最容易出问题的地方.比如对于下面简单的语句,一般 DBA 想到的办法是在 type, name, create_time 字段上加组合索引.

MySQL &#183; 性能优化 &#183; MySQL常见SQL错误用法

前言 MySQL在2016年仍然保持强劲的数据库流行度增长趋势.越来越多的客户将自己的应用建立在MySQL数据库之上,甚至是从Oracle迁移到MySQL上来.但也存在部分客户在使用MySQL数据库的过程中遇到一些比如响应时间慢,CPU打满等情况.阿里云RDS专家服务团队帮助云上客户解决过很多紧急问题.现将<ApsaraDB专家诊断报告>中出现的部分常见SQL问题总结如下,供大家参考. 常见SQL错误用法 1. LIMIT 语句 分页查询是最常用的场景之一,但也通常也是最容易出问题的地方.比如

Java ArrayList、Vector和LinkedList等的差别与用法(转)

Java ArrayList.Vector和LinkedList等的差别与用法(转) ArrayList 和Vector是采取数组体式格式存储数据,此数组元素数大于实际存储的数据以便增长和插入元素,都容许直接序号索引元素,然则插入数据要设计到数组元素移动等内存操纵,所以索引数据快插入数据慢,Vector因为应用了synchronized办法(线程安然)所以机能上比ArrayList要差,LinkedList应用双向链表实现存储,按序号索引数据须要进行向前或向后遍历,然则插入数据时只须要记录本项的

C++成员函数指针错误用法警示(成员函数指针与高性能的C++委托,三篇),附好多评论

今天做一个成绩管理系统的并发引擎,用Qt做的,仿照QtConcurrent搞了个模板基类.这里为了隐藏细节,隔离变化,把并发的东西全部包含在模板基类中.子类只需注册需要并发执行的入口函数即可在单独线程中执行.最终目标是,继承的业务逻辑类外部调用时有两个接口可选,调用syncRun同步执行:调用由引擎自动生成的asyncRun就异步执行.最终自动生成asyncRun的模板基类没能实现,主要原因是mingw对this处理的太有问题了!!原本以为编译器问题,后来才知道成员函数指针和this指针如此特殊

宏的几种特殊用法

1. 屏蔽"未使用参数"警告 在OceanBase中ob_define.h中就使用了这种宏,将传入的数据强制转化为void型. #ifndef UNUSED #define UNUSED(v) ((void)(v)) #endif 这种宏主要是为了屏蔽"未使用参数"的警告,如下面这个函数用两个参数,但是一个都不用的话,某些编译器就会报出警告:认为p和mod_id都没有使用.所有我们使用UNUSE宏,这样两个参数都被使用了,但是实际上没有做任何有效的动作,以此来屏蔽&

PDO 中支持三种错误处理模式:

PDO 支持三种错误处理模式: 静默模式,警告模式,异常模式 静默模式是默认的,需要修改的话,通过设置 PDO 对象的属性完成. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT)? $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING)?? $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT)?

Asp.Net的四种错误处理方法

     Asp.Net的四种错误处理 正文: 局部错误处理:      1.ErroePage属性      或者使用page页面指令:      注意点:为了使Page.ErrorPage 起作用,webconfig文件下的customErrors节点的mode属性必须设置为On. 2.Page_Error事件 全局错误: 3.全局文件: 4.webconfig文件节点配置 Note: RemoteOnly,自定义的错误页面只发送给远程用户,当在服务器本地操作时,发生错误时,程序还是会返回红

A query was run and no Result Maps were found for...原来是mapper.xml文件出了问题,是使用MyBatis最常见的一种错误

今天遇到一个问题,原来是mapper.xml文件出了问题,是使用MyBatis最常见的一种错误 报错的结果是这样的: A query was run and no Result Maps were found for the Mapped Statement 'cn.zrgk.dao.RoleMapper.getRoleList'. It's likely that neither a Result Type nor a Result Map was specified. org.apache.

英语常见介词错误用法,你有犯过吗?

英语常见介词错误用法,你有犯过吗? 1:错:come to here. 对:come here. 过来.here ,there,home之类的副词,前面不用介词in ,at,(但可以加from,比如from home,from here),直接跟在动词come 后面就可以了.2:错:look at the mirror. 对:look in the mirror. 照镜子."看"的英语就是look at 啊?有人会问了.但"照镜子"只能是look in the mi