欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

深入了解java8的foreach循环

程序员文章站 2024-02-16 14:41:40
虽然java8出来很久了,但是之前用的一直也不多,最近正好学习了java8,推荐一本书还是不错的<写给大忙人看的javase8>。因为学习了java8,所以只要...

虽然java8出来很久了,但是之前用的一直也不多,最近正好学习了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:

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循环

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

深入了解java8的foreach循环

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

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

•不要使用java8的foreach,每次耗时高达100毫秒以上

•提前计算出大小的普通for循环,耗时最小,但是书写麻烦

•增强for循环表现良好

2.再次遍历一个set

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

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依然每次耗时100ms以上,最快的变成了增强for循环,iterator遍历和java8的iterator().foreachremaining差不多。

3.最后遍历map

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

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依然不负众望,最快的是增强for循环。

最终结论

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

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

以上所述是小编给大家介绍的java8的foreach循环 ,希望对大家有所帮助