欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java遍歷機(jī)制性能的比較詳解

 更新時(shí)間:2019年06月10日 09:36:07   作者:cartoony  
這篇文章主要給大家介紹了關(guān)于java遍歷機(jī)制性能比較的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

緣由

近段時(shí)間在寫leetcode的Lemonade Change時(shí)候,發(fā)現(xiàn)了for循環(huán)與forEach循環(huán)的耗時(shí)是不一致的,在提交記錄上面差了一倍......

平常開發(fā)絕大部分業(yè)務(wù)邏輯的實(shí)現(xiàn)都需要遍歷機(jī)制的幫忙,雖說(shuō)也有注意到各數(shù)據(jù)結(jié)構(gòu)操作的性能比較,但是忽視了遍歷機(jī)制性能的差異。原本前兩天就開始動(dòng)手寫,拖延癥......

正文

現(xiàn)階段我所知道JAVA遍歷機(jī)制有三種

  • for循環(huán)
  • forEach循環(huán)
  • Iterator循環(huán)

JAVA數(shù)據(jù)結(jié)構(gòu)千千萬(wàn),但是大部分都是對(duì)基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)的封裝,比較HashMap依賴于Node數(shù)組,LinkedList底層是鏈表,ArrayList對(duì)數(shù)組的再封裝......扯遠(yuǎn)了

總結(jié)來(lái)說(shuō),JAVA的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),我覺得有兩種

  • 數(shù)組
  • 鏈表

如果是加上Hash(Hash的操作與數(shù)組以及鏈表不太一致),就是三種

因?yàn)槠匠i_發(fā)大部分都優(yōu)先選擇包裝后的數(shù)據(jù)結(jié)構(gòu),所以下面我會(huì)使用

  • ArrayList(包裝后的數(shù)組)
  • LinkedList(包裝后的鏈表)
  • HashSet(包裝后的Hash類型數(shù)組)

這三種數(shù)據(jù)結(jié)構(gòu)在遍歷機(jī)制不同的時(shí)候時(shí)間的差異

可能有人對(duì)我為什么不對(duì)比HashMap呢,因?yàn)镴AVA設(shè)計(jì)中,是先實(shí)現(xiàn)了Map,再實(shí)現(xiàn)Set。如果你有閱讀過(guò)源碼就會(huì)發(fā)現(xiàn):每個(gè)Set子類的實(shí)現(xiàn)中,都有一個(gè)序列化后的Map對(duì)應(yīng)屬性實(shí)現(xiàn),而因?yàn)镠ash的查找時(shí)間復(fù)雜度為O(1),得出key后查找value的時(shí)間大致是一致的,所以我不對(duì)比HashMap。

題外話

我在閱讀《瘋狂JAVA》讀到:JAVA的設(shè)計(jì)者將Map的內(nèi)部entry數(shù)組中的value設(shè)為null進(jìn)而實(shí)現(xiàn)了Set。因?yàn)槲沂且栽创a以及官方文檔為準(zhǔn),具體我不清楚正確與否,但是因?yàn)镠ash中的key互不相同,Set中元素也互不相同,所以我認(rèn)為這個(gè)觀點(diǎn)是正確的。

為了測(cè)試的公平性,我會(huì)采取以下的限定

每種數(shù)據(jù)結(jié)構(gòu)的大小都設(shè)置三種量級(jí)

  • 10
  • 100
  • 1000

元素都采用隨機(jī)數(shù)生成

遍歷進(jìn)行操作都為輸出當(dāng)前元素的值

注:時(shí)間開銷受本地環(huán)境的影響,可能測(cè)量值會(huì)出現(xiàn)變化,但是總體上比例是正確的

ArrayList的比較

代碼

public class TextArray {

  private static Random random;

  private static List<Integer> list1;

  private static List<Integer> list2;

  private static List<Integer> list3;

  public static void execute(){
    random=new Random();
    initArray();
    testForWith10Object();
    testForEachWith10Object();
    testIteratorWith10Object();
    testForWith100Object();
    testForEachWith100Object();
    testIteratorWith100Object();
    testForWith1000Object();
    testForEachWith1000Object();
    testIteratorWith1000Object();
  }

  private static void testForWith10Object(){
    printFor(list1);
  }

  private static void testForWith100Object(){
    printFor(list2);
  }

  private static void testForWith1000Object(){
    printFor(list3);
  }

  private static void testForEachWith10Object(){
    printForeach(list1);
  }

  private static void testForEachWith100Object(){
    printForeach(list2);
  }

  private static void testForEachWith1000Object(){
    printForeach(list3);
  }

  private static void testIteratorWith10Object() {
    printIterator(list1);
  }

  private static void testIteratorWith100Object() {
    printIterator(list2);
  }

  private static void testIteratorWith1000Object() {
    printIterator(list3);
  }

  private static void printFor(List<Integer> list){
    System.out.println();
    System.out.print("data:");
    long start=System.currentTimeMillis();
    for(int i=0,length=list.size();i<length;i++){
      System.out.print(list.get(i)+" ");
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("for for "+list.size()+":"+(end-start)+"ms");
  }

  private static void printForeach(List<Integer> list){
    System.out.println();
    System.out.print("data:");
    long start=System.currentTimeMillis();
    for(int temp:list){
      System.out.print(temp+" ");
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("foreach for "+list.size()+":"+(end-start)+"ms");
  }

  private static void printIterator(List<Integer> list){
    System.out.println();
    System.out.print("data:");
    Iterator<Integer> it=list.iterator();
    long start=System.currentTimeMillis();
    while(it.hasNext()){
      System.out.print(it.next()+" ");
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("iterator for "+list.size()+":"+(end-start)+"ms");
  }

  private static void initArray(){
    list1=new ArrayList<>();
    list2=new ArrayList<>();
    list3=new ArrayList<>();
    for(int i=0;i<10;i++){
      list1.add(random.nextInt());
    }
    for(int i=0;i<100;i++){
      list2.add(random.nextInt());
    }
    for(int i=0;i<1000;i++){
      list3.add(random.nextInt());
    }
  }
}

輸出(忽略對(duì)元素的輸出)

for for 10:1ms
foreach for 10:0ms
iterator for 10:2ms

for for 100:5ms
foreach for 100:4ms
iterator for 100:12ms

for for 1000:33ms
foreach for 1000:7ms
iterator for 1000:16ms

10 100 1000
for 1ms 5ms 33ms
forEach 0ms 4ms 7ms
Iterator 2ms 12ms 16ms

結(jié)論

    for的性能最不穩(wěn)定,foreach次之,Iterator最好

使用建議

  • 在數(shù)據(jù)量不明確的情況下(可能1w,10w或其他),建議使用Iterator進(jìn)行遍歷
  • 在數(shù)據(jù)量明確且量級(jí)小的時(shí)候,優(yōu)先使用foreach
  • 需要使用索引時(shí),使用遞增變量的開銷比f(wàn)or的要小

LinkedList的比較

代碼

public class TextLinkedList {

  private static Random random;

  private static List<Integer> list1;

  private static List<Integer> list2;

  private static List<Integer> list3;

  public static void execute(){
    random=new Random();
    initList();
    testForWith10Object();
    testForEachWith10Object();
    testIteratorWith10Object();
    testForWith100Object();
    testForEachWith100Object();
    testIteratorWith100Object();
    testForWith1000Object();
    testForEachWith1000Object();
    testIteratorWith1000Object();
  }

  private static void testForWith10Object() {
    printFor(list1);
  }

  private static void testForEachWith10Object() {
    printForeach(list1);
  }

  private static void testIteratorWith10Object() {
    printIterator(list1);
  }

  private static void testForWith100Object() {
    printFor(list2);
  }

  private static void testForEachWith100Object() {
    printForeach(list2);
  }

  private static void testIteratorWith100Object() {
    printIterator(list2);
  }

  private static void testForWith1000Object() {
    printFor(list3);
  }

  private static void testForEachWith1000Object() {
    printForeach(list3);
  }

  private static void testIteratorWith1000Object() {
    printIterator(list3);
  }

  private static void printFor(List<Integer> list){
    System.out.println();
    System.out.print("data:");
    long start=System.currentTimeMillis();
    for(int i=0,size=list.size();i<size;i++){
      System.out.print(list.get(i));
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("for for "+list.size()+":"+(end-start)+"ms");
  }

  private static void printForeach(List<Integer> list){
    System.out.println();
    System.out.print("data:");
    long start=System.currentTimeMillis();
    for(int temp:list){
      System.out.print(temp+" ");
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("foreach for "+list.size()+":"+(end-start)+"ms");
  }

  private static void printIterator(List<Integer> list){
    System.out.println();
    System.out.print("data:");
    Iterator<Integer> it=list.iterator();
    long start=System.currentTimeMillis();
    while(it.hasNext()){
      System.out.print(it.next()+" ");
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("iterator for "+list.size()+":"+(end-start)+"ms");
  }


  private static void initList() {
    list1=new LinkedList<>();
    list2=new LinkedList<>();
    list3=new LinkedList<>();
    for(int i=0;i<10;i++){
      list1.add(random.nextInt());
    }
    for(int i=0;i<100;i++){
      list2.add(random.nextInt());
    }
    for(int i=0;i<1000;i++){
      list3.add(random.nextInt());
    }
  }
}

輸出(忽略對(duì)元素的輸出)

for for 10:0ms
foreach for 10:1ms
iterator for 10:0ms

for for 100:1ms
foreach for 100:0ms
iterator for 100:3ms

for for 1000:23ms
foreach for 1000:25ms
iterator for 1000:4ms

10 100 1000
for 0ms 1ms 23ms
forEach 1ms 0ms 25ms
Iterator 0ms 3ms 4ms

結(jié)論

foreach的性能最不穩(wěn)定,for次之,Iterator最好

使用建議

  • 盡量使用Iterator進(jìn)行遍歷
  • 需要使用索引時(shí),使用遞增變量的開銷比f(wàn)or的要小

HashSet的比較

注:因Hash遍歷算法與其他類型不一致,所以取消了for循環(huán)的比較

代碼

public class TextHash {

  private static Random random;

  private static Set<Integer> set1;

  private static Set<Integer> set2;

  private static Set<Integer> set3;

  public static void execute(){
    random=new Random();
    initHash();
    testIteratorWith10Object();
    testForEachWith10Object();
    testIteratorWith100Object();
    testForEachWith100Object();
    testIteratorWith1000Object();
    testForEachWith1000Object();
  }

  private static void testIteratorWith10Object() {
    printIterator(set1);
  }

  private static void testForEachWith10Object() {
    printForeach(set1);
  }

  private static void testIteratorWith100Object() {
    printIterator(set2);
  }

  private static void testForEachWith100Object() {
    printForeach(set2);
  }

  private static void testIteratorWith1000Object() {
    printIterator(set3);
  }

  private static void testForEachWith1000Object() {
    printForeach(set3);
  }

  private static void initHash() {
    set1=new HashSet<>();
    set2=new HashSet<>();
    set3=new HashSet<>();
    for(int i=0;i<10;i++){
      set1.add(random.nextInt());
    }
    for(int i=0;i<100;i++){
      set2.add(random.nextInt());
    }
    for(int i=0;i<1000;i++){
      set3.add(random.nextInt());
    }
  }

  private static void printIterator(Set<Integer> data){
    System.out.println();
    System.out.print("data:");
    long start=System.currentTimeMillis();
    Iterator<Integer> it=data.iterator();
    while (it.hasNext()){
      System.out.print(it.next()+" ");
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("iterator for "+data.size()+":"+(end-start)+"ms");
  }

  private static void printForeach(Set<Integer> data){
    System.out.println();
    System.out.print("data:");
    long start=System.currentTimeMillis();
    for(int temp:data){
      System.out.print(temp+" ");
    }
    System.out.println();
    long end=System.currentTimeMillis();
    System.out.println("foreach for "+data.size()+":"+(end-start)+"ms");
  }
}

輸出(忽略對(duì)元素的輸出)

iterator for 10:0ms
foreach for 10:0ms

iterator for 100:6ms
foreach for 100:0ms

iterator for 1000:30ms
foreach for 1000:9ms

10 100 1000
foreach 0ms 0ms 9ms
Iterator 0ms 6ms 30ms

結(jié)論

foreach性能遙遙領(lǐng)先于Iterator

使用建議

以后就選foreach了,性能好,寫起來(lái)也方便。

總結(jié)

  • for循環(huán)性能在三者的對(duì)比中總體落于下風(fēng),而且開銷遞增幅度較大。以后即使在需要使用索引時(shí)我寧愿使用遞增變量也不會(huì)使用for了。
  • Iterator的性能在數(shù)組以及鏈表的表現(xiàn)都是最好的,應(yīng)該是JAVA的設(shè)計(jì)者優(yōu)化過(guò)了。在響應(yīng)時(shí)間敏感的情況下(例如web響應(yīng)),優(yōu)先考慮。
  • foreach的性能屬于兩者之間,寫法簡(jiǎn)單,時(shí)間不敏感的情況下我會(huì)盡量選用。

以上就是我對(duì)常見數(shù)據(jù)結(jié)構(gòu)遍歷機(jī)制的一點(diǎn)比較,雖然只是很初步,但是從中我也學(xué)到了很多東西,希望你們也有所收獲。

好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Spring Boot 文件上傳原理解析

    Spring Boot 文件上傳原理解析

    Spring Boot 文件上傳原理其實(shí)就是Spring MVC,因?yàn)檫@部分工作是Spring MVC做的而不是Spring Boot,那么,SpringMVC又是怎么處理文件上傳這個(gè)過(guò)程的呢?下面通過(guò)本文給大家詳細(xì)介紹下,一起看看吧
    2018-03-03
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(10)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(10)

    下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你
    2021-07-07
  • Spring AOP日志框架實(shí)現(xiàn)過(guò)程圖解

    Spring AOP日志框架實(shí)現(xiàn)過(guò)程圖解

    這篇文章主要介紹了Spring AOP日志框架實(shí)現(xiàn)過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • idea中加入git版本控制的方法及步驟詳解

    idea中加入git版本控制的方法及步驟詳解

    在idea中加入git版本控制,方便團(tuán)隊(duì)中多人協(xié)同開發(fā),項(xiàng)目可以同時(shí)方便進(jìn)行管理和迭代。下面就是idea中加入git 的方法和步驟,感興趣的朋友一起看看吧
    2021-09-09
  • Linux系統(tǒng)卸載重裝JDK的完整流程

    Linux系統(tǒng)卸載重裝JDK的完整流程

    Linux系統(tǒng)有時(shí)候會(huì)默認(rèn)使用OpenJDK版本,需要卸載后重新安裝自己需要的JDK版本,下面這篇文章主要給大家介紹了關(guān)于Linux系統(tǒng)卸載重裝JDK的完整流程,需要的朋友可以參考下
    2024-02-02
  • Spring中@Scheduled和HttpClient的連環(huán)坑

    Spring中@Scheduled和HttpClient的連環(huán)坑

    這篇文章主要給大家介紹了關(guān)于Spring中@Scheduled和HttpClient的連環(huán)坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-03-03
  • java  工廠方法詳解及實(shí)例代碼

    java 工廠方法詳解及實(shí)例代碼

    這篇文章主要介紹了java 工廠方法詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • 關(guān)于spring web-mvc衍生注解

    關(guān)于spring web-mvc衍生注解

    這篇文章主要介紹了關(guān)于spring web-mvc衍生注解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • java 棧和堆區(qū)別詳細(xì)介紹

    java 棧和堆區(qū)別詳細(xì)介紹

    這篇文章主要介紹了java 棧和堆區(qū)別詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • 詳解Springboot集成sentinel實(shí)現(xiàn)接口限流入門

    詳解Springboot集成sentinel實(shí)現(xiàn)接口限流入門

    這篇文章主要介紹了詳解Springboot集成sentinel實(shí)現(xiàn)接口限流入門,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評(píng)論