关于Java8的foreach循环

栏目: 编程语言 · Java · 发布时间: 6年前

内容简介:关于Java8的foreach循环

虽然 Java 8出来很久了,但是之前用的一直也不多,最近正好学习了Java8,推荐一本书还是不错的<写给大忙人看的javase8>。因为学习了Java8,所以只要能用到的地方都会去用,尤其是Java8的Stream,感觉用起来觉得很方便,因为点点点就出来了,而且代码那么简洁。现在开始慢慢深入了解Java8,发现很多东西不能看表面。

比如常规遍历一个集合,下面给出例子:

1.首先遍历一个List

方式1.一开始是这样的:

public static void test1(List<String> list) {
  for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
  }
}

方式2.当然稍微高级一点的是这样:

public static void test2(List<String> list) {
  for (int i = 0,lengh=list.size(); i < lengh; i++) {
    System.out.println(list.get(i));
  }
}

方式3.还有就是Iterator遍历:

public static void test3(List<String> list) {
  Iterator<String> iterator = list.iterator();
  while(iterator.hasNext()){
    System.out.println(iterator.next());
  }
}

方式4.后来有了增强for循环:

public static void test4(List<String> list) {
  for(String str:list){
    System.out.println(str);
  }
}

方式5.java8以后新增的方式:

public static void test5(List<String> list) {
  //list.forEach(System.out::println);和下面的写法等价
  list.forEach(str->{
    System.out.println(str);
  });
}

方式6.还有另一种:

public static void test6(List<String> list) {
  list.iterator().forEachRemaining(str->{
    System.out.println(str);
  });
}

应该没有其他的了吧,上面六中方法,按我的使用习惯5最常用,4偶尔使用,其他的基本就不怎么用了,使用5的原因是因为方便书写,提示就可以写出来,偶尔使用4的原因是,5不方便计数用,下面进行性能测试,String不具备代表性,决定使用对象,简单的一个测试类如下:

一个简单的测试,内容不要太在意,简单计算hashCode:

关于Java8的foreach循环
关于Java8的foreach循环
package test;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test8 {
  public static void main(String[] args) {
    List<Dog> list=new ArrayList<>();
    for(int i=0;i<10;i++){
      list.add(new Dog(i,"dog"+i));
    }
    long nanoTime = System.nanoTime();
    test1(list);
    long nanoTime1 = System.nanoTime();
    test2(list);
    long nanoTime2 = System.nanoTime();
    test3(list);
    long nanoTime3 = System.nanoTime();
    test4(list);
    long nanoTime4 = System.nanoTime();
    test5(list);
    long nanoTime5 = System.nanoTime();
    test6(list);
    long nanoTime6 = System.nanoTime();
    
    System.out.println((nanoTime1-nanoTime)/1000000.0);
    System.out.println((nanoTime2-nanoTime1)/1000000.0);
    System.out.println((nanoTime3-nanoTime2)/1000000.0);
    System.out.println((nanoTime4-nanoTime3)/1000000.0);
    System.out.println((nanoTime5-nanoTime4)/1000000.0);
    System.out.println((nanoTime6-nanoTime5)/1000000.0);
  }

public static void test1(List<Dog> list) {
  for (int i = 0; i < list.size(); i++) {
    list.get(i).hashCode();
  }
}
public static void test2(List<Dog> list) {
  for (int i = 0,lengh=list.size(); i < lengh; i++) {
    list.get(i).hashCode();
  }
}
public static void test3(List<Dog> list) {
  Iterator<Dog> iterator = list.iterator();
  while(iterator.hasNext()){
    iterator.next().hashCode();
  }
}
public static void test4(List<Dog> list) {
  for(Dog dog:list){
    dog.hashCode();
  }
}
public static void test5(List<Dog> list) {
  //list.forEach(System.out::println);和下面的写法等价
  list.forEach(dog->{
    dog.hashCode();
  });
}
public static void test6(List<Dog> list) {
  list.iterator().forEachRemaining(dog->{
    dog.hashCode();
  });
}
}
class Dog{
  private int age;
  private String name;
  public Dog(int age, String name) {
    super();
    this.age = age;
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  @Override
  public String toString() {
    return "Dog [age=" + age + ", name=" + name + "]";
  }
}
关于Java8的foreach循环

运行三次取平均值,机器配置就不说了,因为我不是比较的绝对值,我是比较的这几种方式的相对值,数据结果,趋势图如下:

关于Java8的foreach循环

然后去掉表现一直很稳定的方式5和百万级数据量以上的数据,来分析结果:

关于Java8的foreach循环

可以得出一个非常吓人的结果,java8的foreach每次循环的耗时竟然高达100毫秒以上,虽然它比较稳定(算是优点吧)。所以得出以下结论:

在正常使用(数据量少于百万以下), 正常(非并行) 遍历一个集合的时候:

  • 不要使用java8的foreach,每次耗时高达100毫秒以上
  • 提前计算出大小的普通for循环,耗时最小,但是书写麻烦
  • 增强for循环表现良好

2.再次遍历一个Set

使用以相同的方式测试HashSet,测试方法如下:

关于Java8的foreach循环
关于Java8的foreach循环
package test;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Test9 {
  public static void main(String[] args) {
    Set<Dog> set = new HashSet<>();
    for (int i = 0; i < 10_000_000; i++) {
      set.add(new Dog(i, "dog" + i));
    }
    long nanoTime = System.nanoTime();
    test1(set);
    long nanoTime1 = System.nanoTime();
    test2(set);
    long nanoTime2 = System.nanoTime();
    test3(set);
    long nanoTime3 = System.nanoTime();
    test4(set);
    long nanoTime4 = System.nanoTime();

    System.out.println((nanoTime1 - nanoTime) / 1000000.0);
    System.out.println((nanoTime2 - nanoTime1) / 1000000.0);
    System.out.println((nanoTime3 - nanoTime2) / 1000000.0);
    System.out.println((nanoTime4 - nanoTime3) / 1000000.0);
  }

  public static void test1(Set<Dog> list) {
    Iterator<Dog> iterator = list.iterator();
    while (iterator.hasNext()) {
      iterator.next().hashCode();
    }
  }

  public static void test2(Set<Dog> list) {
    for (Dog dog : list) {
      dog.hashCode();
    }
  }

  public static void test3(Set<Dog> list) {
    list.forEach(dog -> {
      dog.hashCode();
    });
  }

  public static void test4(Set<Dog> list) {
    list.iterator().forEachRemaining(dog -> {
      dog.hashCode();
    });
  }
}
关于Java8的foreach循环

经过计算得出如下结果:

关于Java8的foreach循环

不难发现,java8的foreach依然每次耗时100ms以上,最快的变成了增强for循环,Iterator遍历和java8的iterator().forEachRemaining差不多。

3.最后遍历Map

依然使用相同的方式测试Map集合遍历,测试类如下:

关于Java8的foreach循环
关于Java8的foreach循环
package test;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class Test10 {
  public static void main(String[] args) {
    Map<String, Dog> map = new HashMap<>();
    for (int i = 0; i < 1000_000; i++) {
      map.put("dog" + i, new Dog(i, "dog" + i));
    }
    long nanoTime = System.nanoTime();
    test1(map);
    long nanoTime1 = System.nanoTime();
    test2(map);
    long nanoTime2 = System.nanoTime();
    test3(map);
    long nanoTime3 = System.nanoTime();
    test4(map);
    long nanoTime4 = System.nanoTime();

    System.out.println((nanoTime1 - nanoTime) / 1000000.0);
    System.out.println((nanoTime2 - nanoTime1) / 1000000.0);
    System.out.println((nanoTime3 - nanoTime2) / 1000000.0);
    System.out.println((nanoTime4 - nanoTime3) / 1000000.0);
  }

  public static void test1(Map<String, Dog> map) {
    Iterator<Map.Entry<String, Dog>> entries = map.entrySet().iterator();
    while (entries.hasNext()) {
      Map.Entry<String, Dog> entry = entries.next();
      int code=entry.getKey().hashCode()+entry.getValue().hashCode();
    }
  }

  public static void test2(Map<String, Dog> map) {
    for (Map.Entry<String, Dog> entry : map.entrySet()) {
      int code=entry.getKey().hashCode()+entry.getValue().hashCode();
    }
  }

  public static void test3(Map<String, Dog> map) {
    for (String key : map.keySet()) {
      int code=key.hashCode()+map.get(key).hashCode();
    }
  }

  public static void test4(Map<String, Dog> map) {
    map.forEach((key, value) -> {
      int code=key.hashCode()+value.hashCode();
    });
  }
}
关于Java8的foreach循环

结果如下:

关于Java8的foreach循环

java8的foreach依然不负众望,最快的是增强for循环。

+最终结论

普通(数量级10W以下,非并行)遍历一个集合(List、Set、Map)如果在意效率,不要使用java8的foreach,虽然它很方便很优雅

任何时候使用增强for循环是你不二的选择

本文永久更新链接地址 http://www.linuxidc.com/Linux/2017-05/144358.htm


以上所述就是小编给大家介绍的《关于Java8的foreach循环》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Charlotte's Web

Charlotte's Web

E. B. White / Scholastic / 2004 / USD 0.01

This is the tale of how a little girl named Ferm, with the help of a friendly spider, saved her pig, Wilbur, from the usual fate of nice fat little pigs.一起来看看 《Charlotte's Web》 这本书的介绍吧!

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具