Java Web实战篇:增强for循环实现原理和for循环实战性能优化

原创 2018年04月17日 13:57:52

IT实战联盟.jpg

前言

循环就是让我们的程序重复地执行某些业务。在程序设计时,需要处理大量的重复动作,采用循环结构可以降低程序书写的长度和复杂度,可使复杂问题简单化,提高程序的可读性和执行速度。其中,for循环就是循环结构的一种,另外还有while循环和do-while循环语句。但是for循环是开发者最常用的开发方式。

for循环.jpg

一、增强for循环

1. 三种常用for循环

#普通for循环遍历
for (int i = 0; i < list.size(); i++) {
   System.out.print(list.get(i) + ",");
}
#迭代器循环遍历
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
   System.out.print(iterator.next() + ",");
}
#增强for循环
for (Integer i : list) {
   System.out.print(i + ",");
}

2. 增强for循环实现原理

编译前

for (Integer i : list) {
   System.out.print(i + ",");
}

编译后

Integer i;
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
   i = (Integer)iterator.next();        
}

源码解析

Integer i; 定义一个临时变量i
Iterator iterator = list.iterator(); 获取List的迭代器
iterator.hasNext(); 判断迭代器中是否有未遍历过的元素
i = (Integer)iterator.next(); 获取第一个未遍历的元素,赋值给临时变量i
System.out.println(i) 输出临时变量i的值

通过反编译源码,我们看到,其实JAVA中的增强for循环底层是通过迭代器模式来实现的。

3. 注意:增强for循环可能遇到的坑

既然增强for循环通过迭代器实现,那么必然有迭代器的特性。

Java中有fail-fast机制。在使用迭代器遍历元素的时候,在对集合进行删除的时候一定要注意,使用不当有可能发生ConcurrentModificationException,这是一种运行时异常,编译期并不会发生。只有在程序真正运行时才会爆发。

#代码示例
for (UserInfo user : userInfos) {    
   if (user.getId() == 2)     
      userInfos.remove(user);    
}

会抛出ConcurrentModificationException异常。

Iterator是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出
java.util.ConcurrentModificationException异常。

所以 Iterator 在执行的时候是不允许被迭代的对象被改变的。

但你可以使用 Iterator 本身的方法 remove() 来删除对象,Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

正确的在遍历的同时删除元素的示例:

Iterator<UserInfo> userIterator = users.iterator();    
while (userIterator.hasNext()) {    
   UserInfo userInfo = userIterator.next();    
   if (userInfo.getId() == 2)    
       userIterator.remove();//这里要使用Iterator的remove方法移除当前对象,如果使用List的remove方法,则同样会出现ConcurrentModificationException    
}

二、for循环实战性能优化

循环结构让我们操作数组、集合和其他一些有规律的事物变得更加的方便,但是如果我们在实际开发当中运用不合理,可能会给程序的性能带来很大的影响。所以我们还是需要掌握一些技巧来优化我们的代码的。

1. 嵌套循环

1.1 代码示例

优化前代码示例

Long stratTime = System.nanoTime();  
for (int i = 0; i < 10000; i++) {  
    for (int j = 0; j < 10; j++) {  

    }  
}  
Long endTime = System.nanoTime();  
System.out.println("外大内小耗时:"+ (endTime - stratTime));        

优化后代码示例

Long  stratTime = System.nanoTime();  
for (int i = 0; i <10 ; i++) {  
    for (int j = 0; j < 10000; j++) {  

    }  
}  
Long  endTime = System.nanoTime();  
System.out.println("外小内大耗时:"+(endTime - stratTime));   

运行结果:

外大内小耗时:1957590
外小内大耗时:1228223

由运行结果来看采用外大内小的方式性能差距还是比较大的。

1.2 原理

如果遇到分支结构,就可以利用分支目标缓冲器预测并读取指令的目标地址。分支目标缓冲器在程序运行时将动态记录和调整转移指令的目标地址,可以记录多个地址,对其进行表格化管理。当发生转移时,如果分支目标缓冲器中有记录,下一条指令在取指令阶段就会将其作为目标地址。如果记录地址等于实际目标地址,则并行成功;如果记录地址不等于实际目标地址,则流水线被冲洗。同一个分支,多次预测失败,则更新记录的目标地址。因此,分支预测属于“经验主义”或“机会主义”,会存在一定误测。
————摘抄来源<<C++反汇编与逆向分析技术解密>> 4.4.2 分支优化规则

1.3 原理解析
#外小内大
for (int i = 0; i <10 ; i++) {  
    #下面每次循环会预测成功9999次
    #第1次没有预测,最后退出循环时预测失败1次
    #这样的过程重复10次
    for (int j = 0; j < 10000; j++) {  
          a[i][j]++;
    }  
}  
#外大内小
for (int i = 0; i < 10000; i++) {  
    #下面每次循环会预测成功9次
    #第1次没有预测,最后退出循环时预测失败1次
    #这样的过程重复10000次
    for (int j = 0; j < 10; j++) {  
          a[i][j]++;
    }  
}  

2. 消除循环终止判断时的方法调用

2.1 代码示例

未优化前代码示例

Long stratTime = System.nanoTime();  
for (int i = 0; i < list.size(); i++) {  

}  
Long  endTime = System.nanoTime();  
System.out.println("未优化list耗时:"+(endTime - stratTime));  

优化后代码示例

Long  stratTime = System.nanoTime();  
int size = list.size();  
for (int i = 0; i < size; i++) {  

}  
Long  endTime = System.nanoTime();  
System.out.println("优化list耗时:"+(endTime - stratTime));  

运行结果

未优化list耗时:27375  
优化list耗时:2444  
2.2原理
list.size()每次循环都会被执行一次,这无疑会影响程序的性能,所以应该将其放到循环外面,用一个变量来代替,优化前后的对比也很明显。

3. 异常捕获

3.1 代码示例

优化前代码示例

Long stratTime = System.nanoTime();  
for (int i = 0; i < 10000000; i++) {  
    try {  
    } catch (Exception e) {  
    }  
}  
Long  endTime = System.nanoTime();  
System.out.println("在内部捕获异常耗时:"+(endTime - stratTime));  

优化后代码示例

Long  stratTime = System.nanoTime();  
try {  
    for (int i = 0; i < 10000000; i++) {  
    }  
} catch (Exception e) {  

}  
Long  endTime = System.nanoTime();  
System.out.println("在外部捕获异常耗时:"+(endTime - stratTime));  

运行结果

在内部捕获异常耗时:12150142  
在外部捕获异常耗时:1955  
3.2 总结

捕获异常是很耗资源的,所以不要讲try catch放到循环内部,优化后同样有好几个数量级的提升。

结尾

性能优化的内容有很多,代码优化只是其中一小部分,我们在日常开发中应养成良好的编码习惯。接下来会跟大家探讨更多关于性能优化的内容,希望大家积极交流指导。

关注我们

如果需要源码可以关注“IT实战联盟”公号并留言(源码名称+邮箱),小萌看到后会联系作者发送到邮箱,也可以加入交流群和作者互撩哦~~~

【转】Java 增强的For循环,For each的实现原理

原文地址:http://blog.csdn.net/yasi_xi/article/details/25482173#t1 参考: http://blog.csdn.net/a596620...
  • KEY0323
  • KEY0323
  • 2016-03-04 16:30:32
  • 1406

从字节码看Java中for-each循环(增强for循环)实现原理

for-each循环是jdk1.5引入的新的语法功能。并不是所有东西都可以使用这个循环的。可以看下Iterable接口的注释,它说明了除了数组外,其他类想要使用for-each循环必须实现这个接口。这...
  • u011392897
  • u011392897
  • 2017-01-15 16:11:47
  • 2143

Java高级特性之增强for循环(一)

前言 写道 for/in循环就是JDK5.0中所谓的增强For循环,它能对数组和集合进行遍历,使用它会使用你的代码短小而精炼的多。这里将介绍以下内容: 传统的for循环和增强for循环的比...
  • QQ1130141391
  • QQ1130141391
  • 2013-10-09 20:17:49
  • 31209

Java中的增强For循环

增强的for循环是在传统的for循环中增加的强大的迭代功能的循环,是在jdk1.5之后提出来的。     基本语法格式:for(type 变量名:集合变量名){……}     其中:迭代变量必须在()...
  • qq_30507287
  • qq_30507287
  • 2016-06-28 09:01:44
  • 815

Java中增强型for循环的样例和解释

JDK1.5加入的增强for和循环.语法是:for(ElementType element:arrayName){};举个例子:(1)    int[] numArray = { 1, 2, 3, 4...
  • java2000_net
  • java2000_net
  • 2008-09-13 06:17:00
  • 24847

java增强型for循环和普通循环比较

增强型for循环和普通循环比较:      (1)对于非集合类(没有实现 Iterable接口)的数组遍历,增强型for循环和普通循环遍历原理相同,效率相同      (2)对于集合类(实现了It...
  • u010911386
  • u010911386
  • 2016-09-30 15:17:44
  • 3589

java 增强for循环中的删除问题

foreach 是 Java 中的一种语法糖,几乎每一种语言都有一些这样的语法糖来方便程序员进行开发,编译期间以特定的字节码或特定的方式来对这些语法进行处理。能够提高性能,并减少代码出错的几率。在 J...
  • qq_25622107
  • qq_25622107
  • 2017-06-28 14:45:35
  • 862

Java高级特性之增强for循环

前言 写道 for/in循环就是JDK5.0中所谓的增强For循环,它能对数组和集合进行遍历,使用它会使用你的代码短小而精炼的多。这里将介绍以下内容: 传统的for循环和增强for循环的比较 定制自...
  • dear_Alice_moon
  • dear_Alice_moon
  • 2017-03-16 21:09:12
  • 1157

Java Iterator和增强for循环 for each详解

Iterator是Java中的一个迭代器接口(Interface),用来提供标准的Java迭代器 Iterator支持泛型因为集合(Collection)类可以装入的类型是不确定的,从集合中取出的都...
  • shf4715
  • shf4715
  • 2015-07-23 21:30:01
  • 3191

java中使用增强型的for循环有什么好处

从Java5.0开始,Java语言就有称为加强版的for循坏,它能够很容易地逐个运行数组或其他集合的元素。这是个很好的强化功能,因为这是for循环很常见的用途。我们会在讨论非数组的集合时再次看到加强版...
  • fu_manxing
  • fu_manxing
  • 2016-08-11 13:30:05
  • 4838
收藏助手
不良信息举报
您举报文章:Java Web实战篇:增强for循环实现原理和for循环实战性能优化
举报原因:
原因补充:

(最多只允许输入30个字)