应将 list.size() 提前缓存以避免循环中重复调用,尤其对 linkedlist 每次需遍历计数;arraylist 虽为 o(1),但高频场景下缓存仍可提升 5%–15% 性能;配合使用 arraylist、预设容量、jmh 测试及火焰图验证效果。
在高频循环场景中,把 list.size() 这类方法调用从 for 循环条件中移出,能显著减少重复开销,尤其当 list 是 arraylist(常数时间)或 linkedlist(线性时间)时效果更明显——后者每次调用都要遍历链表计数。
提前缓存集合长度,避免每次迭代都计算
Java 中 for (int i = 0; i 在每次迭代都会执行 <code>size() 方法。对 LinkedList 来说,这等于每次多一次 O(n) 遍历;即使对 ArrayList,JVM 未必总内联该调用,仍存在方法分派与边界检查开销。
优化方式很简单:在循环外缓存长度值:
int len = list.size(); for (int i = 0; i
若 list 在循环中不会被修改,这种写法安全且高效;若需动态判断是否继续(如边遍历边删元素),则应改用迭代器或倒序索引。
用增强 for 循环替代传统索引循环(多数场景更优)
增强 for(for (Item item : list))底层由编译器转为迭代器遍历,对 ArrayList 是连续内存读取,CPU 缓存友好;对 LinkedList 虽仍是链式跳转,但避免了重复 size() + get(i) 的双重开销(get(i) 对链表也是 O(n))。
注意:增强 for 不适合需要索引、或需在遍历时修改集合的场景。此时优先考虑:
- 使用
ListIterator安全删除/添加 - 倒序遍历 + 索引删除(
for (int i = list.size()-1; i >= 0; i--)),避免因删除导致的元素位移和索引错乱
针对不可变或只读集合,启用 JIT 友好写法
如果 list 是 final、构造后不再修改(如 Spring 配置列表、静态规则集),JVM 的 C2 编译器可能将其 size() 内联甚至常量化。但不能依赖此行为——主动缓存仍是确定性优化。
还可配合以下实践提升吞吐:
- 用
ArrayList替代LinkedList(除非频繁头插/头删) - 预设初始容量(
new ArrayList(expectedSize)),避免扩容拷贝 - 若逻辑允许,用
Stream.iterate或并行流处理大批量只读数据(注意并行开销阈值)
验证优化效果:别只看单次耗时
微基准测试要用 JMH,禁用预热干扰;观察指标重点是吞吐量(ops/ms)而非平均延迟。例如:
- 对 10 万元素
LinkedList,原写法可能慢 3–5 倍 - 对
ArrayList,差异通常在 5%–15%,但在 QPS 过万的服务中,这点节省会累积成可观 CPU 时间释放
生产环境建议用 Arthas 或 async-profiler 抽样热点,确认 size() 是否真出现在火焰图顶部——避免过早优化无关路径。










