1. Java集合框架基础认知
作为Java开发者,每天打交道最多的莫过于各种集合类了。记得我刚入行时,经常分不清size()和length的区别,在for循环里踩过不少坑。今天我们就来彻底梳理Java中数组与集合的长度获取和遍历方式,这些都是看似基础却影响代码质量的关键细节。
Java集合框架主要分为两大类:单列集合(Collection)和双列集合(Map)。单列集合下又有List和Set两个重要分支。数组虽然不属于集合框架,但作为最基本的数据结构,我们也会将其纳入比较。理解它们的异同对写出高效、安全的代码至关重要。
在实际项目中,集合操作大概占日常编码量的30%以上。根据我的经验统计,集合相关的bug中约有40%是由于长度判断错误或遍历方式不当引起的。比如在电商系统中,错误地使用普通for循环遍历LinkedList导致性能下降;或者在并发场景下,用迭代器遍历时修改集合引发ConcurrentModificationException。
关键认知:数组是定长的连续内存空间,而集合是动态扩容的对象容器。这种本质差异决定了它们在长度获取和遍历方式上的不同。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数组的长度获取与遍历
2.1 数组长度获取的底层原理
Java数组的length属性是个final字段,在数组创建时就被确定。这个设计非常巧妙——数组在内存中是连续分配的,length实际上记录了这块连续内存区域的大小。当我们声明int[] arr = new int[10]时,JVM会在堆中分配一块足以存放10个int值的内存,并将length设为10。
java复制// 数组声明与初始化
String[] strArray = {"Java", "Python", "Go"};
int[] intArray = new int[5];
// 获取长度
int strLength = strArray.length; // 返回3
int intLength = intArray.length; // 返回5
注意length是属性不是方法,所以不需要括号。这是数组与集合在API设计上的明显区别。在Android开发中,我曾见过有人误写array.length()导致编译错误的案例。
2.2 数组遍历的四种方式及性能对比
1. 传统for循环
java复制for(int i=0; i<strArray.length; i++){
System.out.println(strArray[i]);
}
这是最高效的遍历方式,特别是对于基本类型数组。但要注意:
- 循环条件中直接使用
array.length而不是缓存长度,现代JVM会优化这类操作 - 下标从0开始,小心数组越界
2. 增强for循环
java复制for(String str : strArray){
System.out.println(str);
}
语法更简洁,但会创建隐式迭代器,对基本类型数组会有自动装箱开销。在性能敏感场景需谨慎使用。
3. while循环
java复制int i = 0;
while(i < strArray.length){
System.out.println(strArray[i++]);
}
不推荐,容易写出死循环,可读性也不如for循环。
4. 使用Arrays.stream()
java复制Arrays.stream(strArray).forEach(System.out::println);
Java8引入的函数式风格,简洁但性能最差,适合非关键路径代码。
性能测试数据:遍历100万长度的int数组,传统for循环耗时约2ms,增强for循环约5ms,stream方式约50ms。在热点代码中这个差异会被放大。
3. List集合的长度与遍历
3.1 List的size()方法奥秘
所有List实现都通过size()方法返回元素个数,但这个方法的实现原理各不相同:
- ArrayList:直接返回维护的size字段
- LinkedList:需要遍历节点计数(JDK8优化为维护size字段)
- CopyOnWriteArrayList:返回底层数组长度
java复制List<String> arrayList = new
