亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java集合中contains方法的效率對(duì)比分析

 更新時(shí)間:2021年05月26日 15:13:19   作者:zhulj625  
這篇文章主要介紹了Java集合中contains方法的效率對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

最近讓部門(mén)技術(shù)大佬幫忙代碼review的時(shí)候,他給我指出了一個(gè)小的技術(shù)細(xì)節(jié),就是對(duì)于集合的contains方法盡量選用Set而不是List,平時(shí)沒(méi)怎么注意,仔細(xì)看了下源碼,大佬就是大佬,技術(shù)細(xì)節(jié)也把握的死死的。

Java集合List、Set中均有對(duì)集合中元素是否存在的判斷方法contains(Object o);Map中有對(duì)key及value是否存在的判斷方法containsKey(Object key)和containsValue(Object value)。

1.ArrayList

在ArrayList中contains方法通過(guò)遍歷list中的元素,利用==或equals來(lái)判斷是否存在目標(biāo)元素,復(fù)雜度為O(N)

public boolean contains(Object o) {
    return indexOf(o) >= 0;
}
public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

2.HashSet

HashSet中元素以Key的形式存于HashMap中,判斷元素是否存在即是判斷對(duì)應(yīng)Map中key是否存在。

HashSet:
    private transient HashMap<E,Object> map; //將不需要序列化的屬性前添加關(guān)鍵字transient,序列化對(duì)象的時(shí)候,這個(gè)屬性就不會(huì)被序列化。
    /**
     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
     * default initial capacity (16) and load factor (0.75).
     */
    public HashSet() {
        map = new HashMap<>();
    }
public boolean contains(Object o) {
    return map.containsKey(o);
}

3.HashMap

HashMap中有兩個(gè)contains方法,一個(gè)判斷key是否存在,一個(gè)判斷value是否存在。

HashMap的底層主要是基于數(shù)組和鏈表(散列表或者叫哈希表)來(lái)實(shí)現(xiàn)的,它之所以有相當(dāng)快的查詢(xún)速度主要是因?yàn)樗峭ㄟ^(guò)計(jì)算散列碼來(lái)決定存儲(chǔ)的位置。

所以containsKey通過(guò)key的哈希值直接查找key是否存在,時(shí)間復(fù)雜度為O(1),響應(yīng)的HashSet查找元素的時(shí)間復(fù)雜度也是O(1)。

對(duì)于containsValue方法判斷map中是否存在value的判斷,其方法為將map中的Node數(shù)組進(jìn)行遍歷,然后判斷是否存在。

transient Node<K,V>[] table;
public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}
final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
}
public boolean containsValue(Object value) {
        Node<K,V>[] tab; V v;
        if ((tab = table) != null && size > 0) {
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                    if ((v = e.value) == value ||
                        (value != null && value.equals(v)))
                        return true;
                }
            }
        }
        return false;
}

4.總結(jié)

集合各方法的時(shí)間復(fù)雜度 contains containskey containsValue
ArrayList O(N)
HashSet O(1)
HashKey O(1) O(N)

對(duì)于這種技術(shù)細(xì)節(jié)需要平時(shí)注意和積累,不斷學(xué)習(xí)和記錄,應(yīng)用于實(shí)際開(kāi)發(fā)中,不斷提高運(yùn)行效率。后續(xù)也會(huì)將這些技術(shù)細(xì)節(jié)記錄下來(lái),在日常開(kāi)發(fā)中加以運(yùn)用。

補(bǔ)充:ArrayList的contains方法的效率果然不高

看代碼吧~

之前做的一個(gè)項(xiàng)目,數(shù)據(jù)庫(kù)抽出了40多萬(wàn)條數(shù)據(jù),然后從csv文件抽出了大概也是40多萬(wàn)條數(shù)據(jù),進(jìn)行對(duì)比分析 之前代碼如下:

List<String> keys = new ArrayList<String>();
   int isize = msTaiyousr.size();
   for (int i=0;i<isize;i++) {
    Map<String, Object> msyaiyousr = msTaiyousr.get(i);
    String id = (String) msyaiyousr.get("taiyousrid");
    String usrtorokukbn = (String) msyaiyousr.get("usrtorokukbn");
    keys.add(usrtorokukbn+":"+id);
   }   
  
   int jsize = wkTaiyousr.size();
   for (int j=0;j<jsize;j++) {
    Map<String, Object> wktaiyousr = wkTaiyousr.get(j);
    String id = (String) wktaiyousr.get("taiyousrid");
    String usrtorokukbn = (String) wktaiyousr.get("usrtorokukbn");
    if (keys.contains(usrtorokukbn+":"+id)) {
      updateList.add(wktaiyousr);
     } else {
      insertList.add(wktaiyousr);
    }
   }

由于 第二個(gè)for循環(huán)使用了 ArrayList的contains方法,跑完第二個(gè)for循環(huán)使用了 12分鐘左右,我的個(gè)天,第一個(gè)循環(huán)不到1秒。然后使用了 HashSet 代替 ArrayList 代碼如下:

Set<String> keys = new HashSet<String>();
   int isize = msTaiyousr.size();
   for (int i=0;i<isize;i++) {
    Map<String, Object> msyaiyousr = msTaiyousr.get(i);
    String id = (String) msyaiyousr.get("taiyousrid");
    String usrtorokukbn = (String) msyaiyousr.get("usrtorokukbn");
    keys.add(usrtorokukbn+":"+id);
   }
  
   int jsize = wkTaiyousr.size();
   for (int j=0;j<jsize;j++) {
    Map<String, Object> wktaiyousr = wkTaiyousr.get(j);
    String id = (String) wktaiyousr.get("taiyousrid");
    String usrtorokukbn = (String) wktaiyousr.get("usrtorokukbn");
    if (keys.contains(usrtorokukbn+":"+id)) {
      updateList.add(wktaiyousr);
     } else {
      insertList.add(wktaiyousr);
    }
   }

結(jié)果不到1秒,兩個(gè)for循環(huán)瞬間跑完。果然大數(shù)據(jù)的時(shí)候還是不要用到ArrayList的contains方法,改用HashSet的吧。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot多環(huán)境切換的配置實(shí)現(xiàn)

    SpringBoot多環(huán)境切換的配置實(shí)現(xiàn)

    在日常的開(kāi)發(fā)中,一般都會(huì)分好幾種環(huán)境,本文就來(lái)介紹一下SpringBoot多環(huán)境切換的配置實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Java反射獲取實(shí)例的速度對(duì)比分析

    Java反射獲取實(shí)例的速度對(duì)比分析

    這篇文章主要介紹了Java反射獲取實(shí)例的速度對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • SpringBoot解析JSON數(shù)據(jù)的三種方案

    SpringBoot解析JSON數(shù)據(jù)的三種方案

    JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式,易于人閱讀和編寫(xiě),同時(shí)也易于機(jī)器解析和生成,本文給大家介紹了SpringBoot解析JSON數(shù)據(jù)的三種方案,需要的朋友可以參考下
    2024-03-03
  • Redis Java 集成到 Spring Boot的詳細(xì)過(guò)程

    Redis Java 集成到 Spring Boot的詳細(xì)過(guò)程

    本文介紹了如何使用SpringBoot連接Redis,并展示了如何配置Redis服務(wù)地址、創(chuàng)建Controller類(lèi)以及進(jìn)行基本的Redis操作,如字符串、列表、集合、哈希和有序集合,感興趣的朋友跟隨小編一起看看吧
    2024-12-12
  • JDBC 實(shí)現(xiàn)通用的增刪改查基礎(chǔ)類(lèi)方法

    JDBC 實(shí)現(xiàn)通用的增刪改查基礎(chǔ)類(lèi)方法

    下面小編就為大家分享一篇JDBC 實(shí)現(xiàn)通用的增刪改查基礎(chǔ)類(lèi)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Java中IO流使用FileWriter寫(xiě)數(shù)據(jù)基本操作詳解

    Java中IO流使用FileWriter寫(xiě)數(shù)據(jù)基本操作詳解

    這篇文章主要介紹了Java中IO流FileWriter寫(xiě)數(shù)據(jù)操作,FileWriter類(lèi)提供了多種寫(xiě)入字符的方法,包括寫(xiě)入單個(gè)字符、寫(xiě)入字符數(shù)組和寫(xiě)入字符串等,它還提供了一些其他的方法,如刷新緩沖區(qū)、關(guān)閉文件等,需要的朋友可以參考下
    2023-10-10
  • Springboot中@Transactional注解與異常處理機(jī)制方式

    Springboot中@Transactional注解與異常處理機(jī)制方式

    這篇文章主要介紹了Springboot中@Transactional注解與異常處理機(jī)制方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Spring中@Scope的幾種取值方式

    Spring中@Scope的幾種取值方式

    這篇文章主要介紹了Spring中@Scope的幾種取值方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 一文帶你掌握J(rèn)ava開(kāi)發(fā)者如何接入并使用DeepSeek

    一文帶你掌握J(rèn)ava開(kāi)發(fā)者如何接入并使用DeepSeek

    對(duì)于Java開(kāi)發(fā)者來(lái)說(shuō),將DeepSeek集成到項(xiàng)目中,可以極大地提升數(shù)據(jù)處理和分析的效率,下面小編就來(lái)為大家介紹一下具體的調(diào)用方法吧
    2025-03-03
  • 你可能真沒(méi)用過(guò)這些 IDEA 插件(建議收藏)

    你可能真沒(méi)用過(guò)這些 IDEA 插件(建議收藏)

    IDEA 全稱(chēng) IntelliJ IDEA,是java編程語(yǔ)言開(kāi)發(fā)的集成環(huán)境。IntelliJ在業(yè)界被公認(rèn)為最好的java開(kāi)發(fā)工具。這篇文章主要介紹 IDEA 必用插件的安裝及用法,需要的朋友可以參考下
    2020-08-08

最新評(píng)論