1. 程式人生 > >Java集合資料儲存的總結

Java集合資料儲存的總結

一、集合框架

集合是容納資料的容器,java常用的集合體系圖如下。以集合中是否執行重複元素來分,主要有List和Set介面,List集合中可以有重複元素,Set集合集合中的元素不可重複,Iterator和List Iterator是遍歷集合的2個迭代器,Map是儲存Key/Value鍵值對的容器。

這裡寫圖片描述

java集合體系圖

二、迭代器

迭代器的用法寫在後面,這裡說明Iterator和ListIterator的區別:

  1. Iterator在遍歷一個集合的過程中不能修改集合中的物件,ListIterator可以修改物件
  2. ListIterator從後往前遍歷,有hasPrevious()方法,Iterator沒有
  3. ListIterator可以在遍歷過程中進行新增元素操作,Iterator不能,否則會報java.util.ConcurrentModificationException異常。

三、List集合

List集合儲存不唯一、有序的物件,可以操作角標。

3.1 ArrayList

3.1.1內部實現

ArrayList也叫變長陣列,陣列的長度是固定的,ArrayList可以隨著元素的增多長度增加,內部實現為陣列。ArrayList在新增元素時首先會判斷長度,長度不夠時,長度擴充套件到原來到1.5倍,原陣列複製到新陣列。

3.1.2關鍵屬性

屬性 取值或結論
是否允許重複 允許
是否有序 有序
是否允許為空 允許
是否執行緒安全
使用場景 多查詢、少增刪

3.1.3 測試示例

建立一個ArrayList物件,新增5個元素,其中一個為null:

        arrayList.add("a1");
        arrayList.add("a2");
        arrayList.add(null);
        arrayList.add("a3");
        arrayList.add("a4");
        System.out.println(arrayList);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

列印結果:

[a1, a2, null, a3, a4]
  • 1

使用迭代器for迴圈方式遍歷:

        for (Iterator iter=arrayList.iterator();iter.hasNext();){
            System.out.println(iter.next());
        }
  • 1
  • 2
  • 3

使用迭代器while迴圈方式遍歷:

        Iterator iter=arrayList.iterator();
        while (iter.hasNext()){
            System.out.println(iter.next());
        }
  • 1
  • 2
  • 3
  • 4

儲存自定義物件:

public class Boy {

    private String name;
    private int age;
    //省略setter、getter、構造器和toString()方法
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

新增Boy物件到ArrayList中並列印:

 ArrayList<Boy> boys=new ArrayList<>();

        Boy b1=new Boy("Tom",12);
        Boy b2=new Boy("Jack",11);
        Boy b3=new Boy("Mike",15);

        boys.add(b1);
        boys.add(b2);
        boys.add(b3);

        System.out.println(boys);
        Iterator<Boy> iter=boys.iterator();
        while (iter.hasNext()){
            Boy b=iter.next();
            System.out.println(b.getName()+"----"+b.getAge());
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

結果:

[Boy{name='Tom', age=12}, Boy{name='Jack', age=11}, Boy{name='Mike', age=15}]
Tom----12
Jack----11
Mike----15
  • 1
  • 2
  • 3
  • 4
  • 5

3.1.4 轉成執行緒安全

非執行緒安全的ArrayList

ArrayList<String> arrayList = new ArrayList();
  • 1
  • 2

執行緒安全的ArrayList

List arrayList =Collections.synchronizedList(new ArrayList<String>()) ;
  • 1

3.1.5 常用方法

  • clear():移除列表中的所有元素
  • contains(Object o): 包含指定元素
  • get(int index):返回列表中指定位置上的元素
  • indexOf(Object o): 返回列表中首次出現指定元素的索引,如果列表不包含,則返回-1
  • isEmpty():列表為空返回true
  • lastIndexOf(Object o):返回列表中最後一次出現指定元素的索引,如果列表不包含元素則返回-1
  • remove(int index):移除列表中指定位置的元素
  • remove(Object o):移除列表中首次出現的指定元素
  • removeRange(int fromIndex,int toIndex):移除列表中索引在fromIndex(包括)和toIndex(不包括)之間的所有元素。
  • size():返回集合的元素個數
  • set(int index,E element):修改指定位置上的元素
  • toArray():按順序返回包含此列表中所有元素的陣列

3.2 LinkedList

3.2.1內部實現

內部實現為雙向連結串列,刪除和增加速度快,查詢速度慢。

3.2.2關鍵屬性

屬性 取值或結論
是否允許重複 允許
是否有序 有序
是否允許為空 允許
是否執行緒安全
使用場景 多增刪、少查詢

3.2.3 測試示例

LinkedList當作FIFO的佇列使用,也就是常用的add方法新增元素:

        LinkedList quene=new LinkedList();
        quene.add("a");
        quene.add("b");
        quene.add("c");
        quene.add("d");

        System.out.println("列印佇列:"+quene);
        System.out.println("獲取隊頭:"+quene.getFirst());
        System.out.println("獲取隊尾:"+quene.getLast());
        System.out.println("移除隊頭:"+quene.pop());
        System.out.println("移除隊頭之後的佇列:"+quene);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

列印結果:

列印佇列:[a, b, c, d]
獲取隊頭:a
獲取隊尾:d
移除隊頭:a
移除隊頭之後的佇列:[b, c, d]
  • 1
  • 2
  • 3
  • 4
  • 5

LinkedList當作FILO的棧使用:

        LinkedList stack = new LinkedList();

        stack.push("1");
        stack.push("2");
        stack.push("3");
        stack.push("4");

        System.out.println("列印棧:"+stack);

        System.out.println("獲取棧頂元素:"+stack.peek());
        System.out.println("列印棧:"+stack);
        System.out.println("取出棧頂元素:"+stack.pop());
        System.out.println("列印棧:"+stack);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

列印結果:

列印棧:[4, 3, 2, 1]
獲取棧頂元素:4
列印棧:[4, 3, 2, 1]
取出棧頂元素:4
列印棧:[3, 2, 1]
  • 1
  • 2
  • 3
  • 4
  • 5

除了ArrayList中包含的基本方法以為,LinkedList中多了getFirst()、getLast()、addFirst()、addLast()、peek()、peekFirst()、peekLast()、removeFirst()、removeLast()等方法。

3.2.4 轉成執行緒安全

 List<Integer> linkedList=Collections.synchronizedList(new LinkedList<Integer>());
  • 1

3.3 Vector

Vector內部是陣列結構,執行緒安全,速度較慢,幾乎不用。

四、Set集合

Set集合中的元素唯一、無序,沒有角標。

4.1HashSet

4.1.1內部實現

內部結構是雜湊表,物件存入HashSet之前,要先確保物件重寫equals()和hashCode()方法,這樣才能比較物件的值是否相等,確保set中沒有儲存相同的物件。判斷兩個元素是否相同,首先通過hashCode()方法判斷的是2個元素的雜湊值是否相同,再根據equals()方法判斷值是否相同,只有2者都相同才是統一元素。

4.1.2 基本屬性

屬性 取值或結論
是否允許重複 不允許
是否有序 無序
是否允許為空 允許(只有一個null)
是否執行緒安全
使用場景 物件不重複和需要快速查詢的場景

4.1.3 測試示例

        HashSet<String> hashSet=new HashSet();
        hashSet.add("abc");
        hashSet.add("張三");
        hashSet.add("李四");
        hashSet.add("tim");
        hashSet.add(null);
        hashSet.add(null);

        System.out.println("HashSet 大小:"+hashSet.size());
        Iterator iter=hashSet.iterator();
        while (iter.hasNext()){
            System.out.println(iter.next());
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

列印結果:

HashSet 大小:5
null
李四
張三
abc
tim
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

新增自定義物件,仍然新增Boy類中的物件

      Boy b1=new Boy("神樂",12);
      Boy b2=new Boy("神樂",12);
      HashSet<Boy> boys=new HashSet<>();
      boys.add(b1);
      boys.add(b2);
      System.out.println(boys);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

結果:

[Boy{name='神樂', age=12}, Boy{name='神樂', age=12}]
  • 1

這時候b1和b2其實是一個物件,在Boy類中重寫hashCode()和equals()方法:

public class Boy {

    private String name;
    private int age;
    //省略setter、getter、構造器和toString()方法
        @Override
    public int hashCode() {

        return name.hashCode()+age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this==obj) return  true;
        if (!(obj instanceof Boy))  throw new ClassCastException("型別錯誤");
        Boy boy=(Boy) obj;

        return this.name.equals(boy.name)&&(this.age==boy.age);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

重寫equals和hashCode方法以後,上述集合中就會只新增一個物件:

[Boy{name='神樂', age=12}]
  • 1

4.1.4 轉成執行緒安全

Set<String> hSet=Collections.synchronizedSet(new HashSet<String>());
  • 1

4.1.5 唯一且有序

LinkedHashSet集合中都元素唯一且有序,這裡都有序是指新增順序。

        LinkedHashSet<String> lHashSet= new LinkedHashSet<String>();
        lHashSet.add("abc");
        lHashSet.add("張三");
        lHashSet.add("李四");
        lHashSet.add("tim");
        lHashSet.add(null);
        iter=lHashSet.iterator();
        while (iter.hasNext()){
            System.out.println(iter.next());
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

列印結果:

abc
張三
李四
tim
null
  • 1
  • 2
  • 3
  • 4
  • 5

4.2 TreeSet

4.2.1 內部實現

TreeSet內部實現為二叉樹,可以對元素進行排序

4.2.2 基本屬性

屬性 取值或結論
是否允許重複 不允許
是否有序 無序
是否允許為空 允許(只有一個null)
是否執行緒安全
使用場景 去重且排序

4.2.3 測試示例


        Boy b1=new Boy("定春",16);
        Boy b2=new Boy("神樂",12);
        Boy b3=new Boy("桑巴",13);

        TreeSet<Boy> treeSet=new TreeSet<>(new Comparator<Boy>() {
            @Override
            public int compare(Boy o1, Boy o2) {
                return o1.getAge()-o2.getAge();
            }
        });

        treeSet.add(b1);
        treeSet.add(b2);
        treeSet.add(b3);
        System.out.println(treeSet);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

列印結果:

[Boy{name='神樂', age=12}, Boy{name='桑巴', age=13}, Boy{name='定春', age=16}]
  • 1

4.2.4 轉成執行緒安全

        TreeSet<Boy> treeSet=new TreeSet<>(new Comparator<Boy>() {
            @Override
            public int compare(Boy o1, Boy o2) {
                return o1.getAge()-o2.getAge();
            }
        });

        Set<Boy> treeSet1=Collections.synchronizedSet(treeSet);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

五、Map集合

Map只儲存的是鍵值對,Key必須唯一且不為空,key允許為null。

5.1HashMap

5.1.1基本屬性

屬性 取值或結論
是否允許重複 key重複會被覆蓋,value可重複
是否有序 無序
是否允許為空 key和value都允許為空
是否執行緒安全

5.1.2 測試示例

詞頻統計:

        String[] arr={"Hadoop","Lucene","ES","ES","ES","Hadoop","Java","JS"};
        //TreeMap<String,Integer> map=new TreeMap<>();
        HashMap<String,Integer> map=new HashMap<>();
        for (String str:arr){
            if (map.containsKey(str)){
                map.put(str,map.get(str)+1);
            }else{
                map.put(str,1);
            }
        }

        Set<String> keys=map.keySet();
        Iterator<String> iter=keys.iterator();
        while (iter.hasNext()){
            String str=iter.next();
            System.out.println(str+"---"+map.get(str));
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

列印結果:

Java---1
Hadoop---2
JS---1
Lucene---1
ES---3
  • 1
  • 2
  • 3
  • 4
  • 5

如果想按value排序,可以改成TreeMap();

六、效能對比

ArrayList遍歷效能對比

ArrayList的遍歷可以用一般for迴圈、foreach迴圈、Iterator迭代器三種方式實現,為了測試它們的效能,先建立一個ArrayList物件,新增5萬個字串:

ArrayList<String > a = new ArrayList();
for (int i = 0; i < 60000; i++) {
    a.add(""+i);
}
  • 1
  • 2
  • 3
  • 4

for 迴圈列印並記錄耗時:

long start = System.currentTimeMillis();

for (int i = 0; i < a.size(); i++) {
     System.out.print(a.get(i));
}

long end = System.currentTimeMillis();

System.out.println("\n下標for迴圈:" + (end - start));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

結果:

150
  • 1

foreach迴圈列印並記錄耗時:

 start = System.currentTimeMillis();

 for (String i : a) {
      System.out.print(i);
 }
 end = System.currentTimeMillis();

 System.out.println("\nforeach:" + (end - start));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

耗時:

95
  • 1

Iterator迴圈列印:

start=System.currentTimeMillis();
Iterator iter=a.iterator();
while (iter.hasNext()){
     System.out.print(iter.next());
}
end=System.currentTimeMillis();
System.out.println("\nIter:"+(end-start));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

耗時:

60
  • 1

結論:一般for 迴圈最慢、foreach次之、Iterator最快。

另外,Iterator遍歷還有另外一種變形方式,效率和while形式一樣。

for(Iterator it=a.iterator();it.hasNext();){
    System.out.print(it.next());
}
  • 1
  • 2
  • 3

七、參考文章

有些文章總結的很好,列出來供參考學習:
Java集合框架

相關推薦

Java集合資料儲存總結

一、集合框架 集合是容納資料的容器,java常用的集合體系圖如下。以集合中是否執行重複元素來分,主要有List和Set介面,List集合中可以有重複元素,Set集合集合中的元素不可重複,Iterator和List Iterator是遍歷集合的2個迭代器,Map是儲存Key/

Java集合框架知識總結

log 增強for循環 stat sort 訪問 字符串 繼承 操作類 map對象 兩大體系:Collection,Map 一、Collection: List 接口 :   List:裏面對象全部是有序的(通過三種方法來遍歷)    ArrayList,LinkedLis

java-集合各個特點總結

alt inf 集合 技術 技術分享 png div http mage java-集合各個特點總結

Java資料結構總結

 Java 基本資料型別總結 在Java的程式碼重構中,我們不得不承認若是不瞭解jvm的記憶體原理或是資料型別,我們根本讀不懂那些亂七八糟的資料引數。 變數就是申請記憶體來儲存值。也就是說,當建立變數的時候,需要在記憶體中申請空間;記憶體管理系統根據變數的型別為變數分配儲存空間

Java集合類的總結

依照實現介面分類: 實現Map介面的有:EnumMap、IdentityHashMap、HashMap、LinkedHashMap、WeakHashMap、TreeMap 實現List介面的有:ArrayList、LinkedList 實現Set介面的有:HashSet、Linke

java集合之List總結

主要驗證一下List集合的常用操作: list中新增,獲取,刪除元素; 新增方法是:.add(e);  獲取方法是:.get(index);  刪除方法是:.remove(index); 按照索引刪除;  .remove(Object o); 按照元素內容刪除;

Java集合框架:總結

Java集合框架這個系列做了一個整理,主要包括: Map系:HashMap, LinkedHashMap, TreeMap, WeakHashMap, EnumMap; List系:ArrayList, LinkedList, Vector, Stack; Set系:HashSet, L

Java 集合 ,資料結構概述

collection集合分類: collection集合的遍歷: 使用迭代器進行遍歷 使用size()和get()方法結合進行遍歷 使用列表迭代器進行遍歷 用toArray()方法將集合轉化成陣列遍歷 注意:用列表迭代器進行遍歷時hasPrevious是判斷

Java集合類的總結與比較

Collection├List│├LinkedList│├ArrayList│└Vector│└Stack└Set Map├Hashtable├HashMap└WeakHashMap Collection介面Collection是最基本的集合介面,一個Collection代

Java集合框架問題總結

1.Java集合框架是什麼?說出一些集合框架的優點? 每種程式語言中都有集合,最初的Java版本包含幾種集合類:Vector、Stack、HashTable和Array。隨著集合的廣泛使用,Java1.2提出了囊括所有集合介面、實現和演算法的集合框架。在保證執行緒安全的情況

Java常用資料結構總結

資料元素相互之間的關係稱為結構。有四類基本結構:集合、線性結構、樹形結構、圖狀結構;集合結構:除了同屬於一種類型外,別無其它關係線性結構:元素之間存在一對一關係常見型別有: 陣列,連結串列,佇列,棧,它

JAVA集合框架學習總結

做一個JAVA簡單的集合框架的知識總結,只是單純的知識點記錄和自己的表達,更深入或具體的只能自己去查API或原始碼了,以後如果有其他想法再回來補充修正,有錯誤之處請指教。 java集合框架主要分為實現了Collection介面的List和Set、對映介面Map。  

[Java]集合框架知識點總結(逐步更新)

1.迭代器 迭代器是一個介面,是一種取出集合中元素的方式。每個集合的內部以內部類的方式實現了此介面,用於取出集合的元素。這些內部類都符合迭代器介面。集合通過一個iterator方法提供這個取出元素的方式。不同的集合因為底層資料結構不同,而實現取出元素的方式不同。但都符合此介

Java集合 他人的總結 和 我的學習

 以下網址是他人的總結, 值得我們學習!  感謝這些人的技術總結!  為什麼引入泛型: java 深入學習 JVM原理: Java類載入器:

Java泛型( 表示集合儲存資料的型別)

1.儲存字串 //建立一個集合儲存abcd //<E>就代表儲存元素資料的型別 //後面的<> 要跟前面的泛型保持一致 //jdk1.7出來的 菱形泛型 //如果前面聲明瞭泛型,後面的泛型可以省略不寫

Java集合框架篇-59-TreeSet儲存基本資料型別和自定義類物件

      這篇開始,我們來學習Set介面的另外一個實現子類TreeSet。TreeSet一般是需要排序才使用的一種集合儲存方式,由於繼承了Set介面,TreeSet也能實現元素的唯一。下面通過兩個練習

Java集合總結

tree dex trac emp oat err 條件 最終 一個地方 集合類和接口之間的關系圖,能夠比較清楚的展示各個類和接口之間的關系(其中:點框為接口(...) 短橫線框為抽象類(---) 實線為類) 上圖可以看到:集合可以分成兩部分來學習。一個是以Colle

Java集合類操作優化經驗總結

設置 mar ise long 初始化 實際類型 線性表 core 不一定 在實際的項目開發中會有非常多的對象,怎樣高效、方便地管理對象,成為影響程序性能與可維護性的重要環節。Java 提供了集合框架來解決此類問題。線性表、鏈表、哈希表等是經常使用的數據結構,在

Java中的常用集合類型總結

tar tro arr style spa htable blog html hset 1.可重復列表(List) LinkedList和ArrayList的區別:http://www.importnew.com/6629.html ArrayList vs. Linked

Java集合總結

存儲方式 hashtable 存在 href city tab 分離 很快 定義 參考博客:  http://www.jianshu.com/p/63e76826e852  http://www.cnblogs.com/LittleHann/p/3690187.html