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垃圾回收器的时候,显得尤为重要。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· C#/.NET/.NET Core技术前沿周刊 | 第 23 期(2025年1.20-1.26)
· 程序员常用高效实用工具推荐,办公效率提升利器!