for循环是java出生的时候就已经支持了,在jdk 1.5中开始支持 foreach 循环,foreach 在一定程度上简化了集合的遍历,但是由于场景的局限性不能完全替代 for 循环,stream是jdk 1.8中开始支持的,功能强大,效率也还行。
public static void main(String[] args) {
List<Integer> array = new ArrayList<Integer>();
List<Integer> link = new LinkedList<Integer>();
long startTime = 0;
long endTime = 0;
int num = 150000;
startTime=System.currentTimeMillis();
for(int i=0; i<num; i++) {
array.add(i);
}
endTime=System.currentTimeMillis();
System.out.println("ArrayList add 花费时间: " + (endTime - startTime));
startTime=System.currentTimeMillis();
for(int i=0; i<num; i++) {
link.add(i);
}
endTime=System.currentTimeMillis();
System.out.println("LinkedList add 花费时间: " + (endTime - startTime));
startTime=System.currentTimeMillis();
for(int i=0; i<num; i++) {
array.get(i);
}
endTime=System.currentTimeMillis();
System.out.println("for 遍历 ArrayList get 花费时间: " + (endTime - startTime));
startTime=System.currentTimeMillis();
for(int i=0; i<num; i++) {
link.get(i);
}
endTime=System.currentTimeMillis();
System.out.println("for 遍历 LinkedList get 花费时间: " + (endTime - startTime));
startTime=System.currentTimeMillis();
for(int i : array) {
// System.out.print(i+"\r");
}
endTime=System.currentTimeMillis();
System.out.println("forEach 遍历 ArrayList get 花费时间: " + (endTime - startTime));
startTime=System.currentTimeMillis();
for(int i : link) {
// System.out.print(i+"\r");
}
endTime=System.currentTimeMillis();
System.out.println("forEach 遍历 LinkedList get 花费时间: " + (endTime - startTime));
startTime=System.currentTimeMillis();
array.stream().forEach(item -> {});
endTime=System.currentTimeMillis();
System.out.println("stream 遍历 LinkedList get 花费时间: " + (endTime - startTime));
startTime=System.currentTimeMillis();
link.stream().forEach(item -> {});
endTime=System.currentTimeMillis();
System.out.println("stream 遍历 LinkedList get 花费时间: " + (endTime - startTime));
}
运行结果
ArrayList:ArrayList是采用数组的形式保存对象的,这种方式将对象放在连续的内存块中,所以插入和删除时比较麻烦,当然在新增的时候遇到需要扩容也是麻烦的,查询比较方便。 LinkList:LinkList是将对象放在独立的空间中,而且每个空间中还保存前后一个空间的索引,也就是数据结构中的链表结构,插入和删除比较方便,但是查找很麻烦,要从第一个开始遍历。
运行结果表明
- 用for循环arrayList 15万次花费时间:3毫秒;用for循环linkList 15万次花费时间:9579毫秒。
- 用foreach循环arrayList 15万次花费时间:5毫秒;用foreach循环linkList 15万次花费时间:2毫秒。
- 用stream中foreach循环arrayList 15万次花费时间:37毫秒。 用foreach循环linkList 15万次花费时间:3毫秒。
循环ArrayList时,普通for循环比foreach循环花费的时间要少一点,stream耗时明显偏大。 循环LinkList时,stream和foreach循环花费的时间差不多,普通for耗时明显大了好多倍。
for循环是通过下标来遍历获取对应的元素,ArrayList是数组结果所以下标获取很快,LinkedList是链表结构,每次通过下标去获取是都是从第一个节点开始往后查找,所以耗时多。 foreach循环是通过迭代器来遍历的,遍历ArrayList时需要先将数组转为对应的引用类型,因为数组没有实现Iterable接口,遍历LinkedList时直接通过顺序IO来遍历的,所以遍历耗时差不多。 stream循环是通过可分迭代器Spliterator来遍历,分为并行流和普通的顺序流,为了实现强大的功能必然对性能有所影响,所以并不是最快的。
结论
- 需要循环数组结构的数据时,建议使用普通for循环,因为for循环采用下标访问,对于数组结构的数据来说,采用下标访问稍微好点,而且还可以满足对list本身的修改。
- 需要循环链表结构的数据时,一定不要使用普通for循环,这种做法很糟糕,数据量大的时候有可能会导致系统崩溃,foreach循环性能虽好但是无法修改list本身,可以优先考虑使用stream。
|