Java集合看了這篇爛文 就夠了(不要臉的說)

weixin_34321977發表於2018-09-13

由於自己不斷受挫,最近在深惡補Java 基礎,感覺集合的魅力深深的吸引了我,我來記錄一下最近的學習筆記,同時分享給大家:

提個名詞,或許你知道 陣列, 在不認識集合之前儲存大量物件,一般使用的就是陣列,但是呢眾所周知陣列如果進行動態的改變即增加或者刪除元素 時,會導致很不方便。大概由於這個原因吧,產生了集合這種 interesting 的容器,下面我們聊聊集合那些事。


6433394-a3d21fa7f7d06ddf.png
偷來的集合框架圖

一、關於 Collection 介面 的那些事

1、常識

集合中儲存的東西,被稱之為物件,也可以稱之為元素。Collection 是集合的頂層介面,他的具體實現類存取的元素,有唯一的、有序的、也有無序的。

2、Collection 的具體功能描述

1)、新增功能
boolean add(E e) 新增單個元素
boolean addAll(Collection c) 新增一個集合元素
2)、刪除功能
void clear() 刪除集合內所有元素
boolean remove(Object o)移除一個元素
boolean removeAll(Collection c)移除集合內資料
3)、判讀功能
boolean contains(Object o)判讀集合內是否包含指定元素
boolean containsAll(Collection c)判斷集合中包含指定集合的集合元素
boolean isEmpty()判斷集合是否為空
4)、獲取功能
Iterator<E> iterator() 迭代
5)、測量長度
int size()返回集合內元素的數量
6)、交集
boolean retainAll(Collection c)兩個集合內公共的元素即兩個集合包含的相同元素

3、方法使用演示

由於 Collection 是個介面並且沒有子介面,那麼我們就用它的子介面的實現類,ArrayList就很好,下面開始我的表演

1、 add(E e)方法
    //新增功能
    private static void collectionTest() {
        Collection<String> ct = new ArrayList<>();
        boolean what = ct.add("北京");
        ct.add("天津");
        ct.add("上海");
        ct.add("河北");
        ct.add("山東");
        ct.add("山西");
        System.out.println("what:" + what + "   集合內容:" + ct);
    }
6433394-a83a8030d872b922.png
執行結果

可以看出,新增成功返回值為 true。

2、clear()方法
  Collection<String> ct = new ArrayList<>();
        boolean what = ct.add("北京");
        ct.add("天津");
        ct.add("上海");
        ct.add("河北");
        ct.add("山東");
        ct.add("山西");
        System.out.println("what:" + what + "   集合內容:" + ct);

        //移除功能
        ct.clear();
        System.out.println("clear 之後的集合:" + ct);
6433394-9fb1e990091334ea.png
移除之後的結果

呼叫 clear() 方法之後 集合內資料被清空

3、remove()方法
  Collection<String> ct = new ArrayList<>();
        boolean what = ct.add("北京");
        ct.add("天津");
        ct.add("上海");
        ct.add("河北");
        ct.add("山東");
        ct.add("山西");
        System.out.println("what:" + what + "   集合內容:" + ct);
        //移除指定元素
        ct.remove("天津");
        System.out.println("移除指定元素之後:"+ct);
6433394-d71fd5d126036f2e.png
移除指定元素

remove 方法:當移除成功時返回值為true,當移除失敗 返回 false(當集合內不包含指定元素則移除失敗)

4、contains(Object o)方法
  Collection<String> ct = new ArrayList<>();
        ct.add("北京");
        ct.add("天津");
        ct.add("上海");
        ct.add("河北");
        ct.add("山東");
        ct.add("山西");
        System.out.println( "集合內容:" + ct);
        //判斷包含
        boolean what = ct.contains("天津");
        System.out.println("what:" + what +"  呼叫方法之後集合:" + ct);
6433394-6885cacf5024a234.png
判斷包含的結果

可以看出來,當包含元素時,返回為true,否則為false

5、size()和 isEmpty() 方法

size()方法類似,陣列的 length()方法
isEmpty()方法 只是對集合進行的判空,是空的則返回 true,否則為 false

6、addAll()方法
  Collection<String> ct = new ArrayList<>();
        ct.add("北京");
        ct.add("天津");
        ct.add("上海");
        ct.add("河北");
        ct.add("山東");
        ct.add("山西");
        System.out.println("ct 集合內容:" + ct);
        //判斷包含
        Collection<String> ctAdd = new ArrayList<>();
        ctAdd.addAll(ct);
        System.out.println("ctAdd 集合內容:" + ctAdd);
6433394-8850bf457f4df04e.png
方法效果展示

由此可以推斷出
boolean removeAll(Collection c)方法和boolean containsAll(Collection c)方法均是將整個集合進行相關操作,返回值表示是否操作成功

7、集合的遍歷

1)、轉換集合為陣列進行相關操作

  Collection<String> ct = new ArrayList<>();
        ct.add("beijing");
        ct.add("tianjin");
        ct.add("shanghai");
        ct.add("hebei");
        ct.add("shandong");
        ct.add("shanxi");
        System.out.println("ct 集合內容:" + ct);

        Object[] o = ct.toArray();

        for (int i = 0; i < ct.size(); i++) {
            System.out.println("O 陣列內容:" + o[i]);
        }
6433394-3d2bc711e46dfb81.png
執行結果

2)、迭代器

        ct.add("北京");
        ct.add("天津");
        ct.add("上海");
        ct.add("河北");
        ct.add("山東");
        ct.add("山西");
        System.out.println("ct 集合內容:" + ct);

        Iterator<String> iterator = ct.iterator();

        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("遍歷結果:" + obj);
        }

使用 Iterator 物件對 集合內資料進行遍歷輸出,是常用的遍歷手段。

其中 hasNext() 方法為判斷遍歷集合是否包含下一個元素。

next() 方法為查詢下一個元素。

通過集合獲取迭代器物件的過程本質上是直接拿到集合,然後在集合內進行相關操作。

總結:遍歷集合的步驟大概總結為: a、擁有一個非空集合; b、通過集合物件回去迭代器物件; c、通過迭代器的 hasNext()方法判讀是否還有下一個物件;d、通過迭代器的 next()方法獲取元素並且移動到下一個位置。

二、List 的那些事

1、常識

List 是 一個有序的 Collection 的介面,這裡的有序指的是,新增到集合和從集合內取出的順序是有序的。

2、方法使用與演示

由於List 整合 Collection 介面,所以父介面有得方法,它都有了,物件導向三大特性,你懂得。下面我們說一下特有的方法吧
1)、新增功能
void add(int index, Object o) 集合指定位置新增元素
2)、獲取功能
Object get(int index) 根據索引獲取元素
int indexOf(Object o)獲取集合內第一次出現元素的索引
int lastIndexOf(Object o) 獲取集合內最後一次出現指定元素的索引
3)、迭代功能
ListIterator listIteretor()List 集合的特有迭代器
4)、刪除功能
Object remove(int index)刪除指定位置元素並返回
5)、擷取功能
subList(int startIndex, int endIndex)擷取集合內兩個索引之間的資料

3、方法演示

1、void add(int index, Object o) 方法
 List<String> list = new ArrayList<>();
        list.add("北京");
        list.add("天津");
        list.add("上海");
        list.add("河北");
        list.add("山東");
        list.add("山西");


        System.out.println("list 集合內容:" + list);

        list.add(0,"中國");

        System.out.println("list 集合插入元素後:" + list);
6433394-c468d1eda53dbccb.png
演示例項

但是該方法使用的索引必須的最大值只能等於集合的長度,否則會:
6433394-d4ccb3d72e780ec1.png
陣列下標越界
2、Object get(int index) 方法
   List<String> list = new ArrayList<>();
        list.add("北京");
        list.add("天津");
        list.add("上海");
        list.add("河北");
        list.add("山東");
        list.add("山西");


        System.out.println("list 集合內容:" + list);

        String s=list.get(2);
        System.out.println("list 得到的資料:" + s);
6433394-61845e81254729a9.png
執行結果

該方法,如果獲取的元素的索引大於集合的長度,則會 陣列下標越界。

3、列表迭代器 ListIterator listIteretor()
   List<String> list = new ArrayList<>();
        list.add("北京");
        list.add("天津");
        list.add("上海");
        list.add("河北");
        list.add("山東");
        list.add("山西");


        System.out.println("list 集合內容:" + list);

        ListIterator<String> lit = list.listIterator();

        while (lit.hasNext()) {
            String s = lit.next();
            System.out.println("正向迭代出來的資料:" + s);
        }
        System.out.println("-------------------------------");
        while (lit.hasPrevious()) {
            String s = lit.previous();
            System.out.println("逆向迭代出來的資料:" + s);
        }
6433394-cc0f12eee5cefebd.png
使用效果

這個迭代器可以進行倒序迭代,但是呢,前提必須是之前進行過正序迭代之後,才可以。

三、ArrayList 的那些事兒

1、常識

ArrayList: 底層為陣列實現,查詢速度快,增刪慢,執行緒不安全,效率高。

2、方法演示

ArrayList 沒有什麼特別的方法,使用 ArrayList 和使用 List 沒什麼特別的區別,建議研究透徹 List 介面 即可很熟練的使用 ArrayList 。

四、Vector 類的那些事兒

1、常識

底層實現為陣列 ,查詢快 、增刪慢 、執行緒安全、效率低

2、特有方法

1)、新增功能
void addElement(Object o)新增元素
2)、獲取功能
Object elementAt(int index)獲取指定位置元素

Enumeration elements()類似於迭代器

3、方法演示

   Vector<String> vector = new Vector<>();
        vector.addElement("北京");
        vector.addElement("天津");
        vector.addElement("上海");
        vector.addElement("河北");
        vector.addElement("山東");
        vector.addElement("山西");

        System.out.println("vector 集合內容:" + vector);

        for (int i = 0; i < vector.size(); i++) {
            System.out.println("for 迴圈遍歷產生的第" + i + "個資料:" + vector.elementAt(i));
        }

        System.out.println("-------------------------------");

        Enumeration<String> enumeration = vector.elements();
        while (enumeration.hasMoreElements()) {
            System.out.println("Enumeration 遍歷產生資料:" + enumeration.nextElement());
        }
6433394-ef9c08882cb6b3c2.png
效果展示

ArrayList 的出現就是為了替代 Vector 集合的。所以這兩個類的各種功能很相似。

五、LinkedList 類的那些事

1、常識

頂層為連結串列實現、查詢慢、增刪快、執行緒不安全、效率高

2、特有方法

1)、增加功能
void addFirst(Object o)在集合首端新增元素
void addLast(Object o)在集合的末尾新增元素
2)、獲取功能
Object getFirst()獲取集合第一個元素
Object getLast()獲取集合最後一個元素
3)、刪除功能
Object removeFirst()移除第一個
Object removeLast()移除最後一個

3、方法演示

    LinkedList<String> linkedList = new LinkedList<>();
        linkedList.add("北京");
        linkedList.add("天津");
        linkedList.add("上海");
        linkedList.add("河北");
        linkedList.add("山東");
        linkedList.add("山西");

        System.out.println("linkedList 集合內容:" + linkedList);

        linkedList.addFirst("中國");
        linkedList.addLast("臺灣");

        System.out.println("新增首尾的 linkedList集合:"+linkedList);
6433394-3856a5f2a7069429.png
效果展示

這裡不再重複移除功能和獲取功能,三種功能類似。

總結:

到這裡 List 的分支已經說的差不多了,下面我們來實際運用一下。

需求:去除集合內的重複元素

實現需求:

1)、建立新集合方式的去重

   List<String> list = new ArrayList<>();
        list.add("北京");
        list.add("天津");
        list.add("上海");
        list.add("河北");
        list.add("河北");
        list.add("河北");
        list.add("河北");
        list.add("山東");
        list.add("山西");

        System.out.println("原有資料:" + list);

        List<String> list1New = new ArrayList<>();

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {

            String s = iterator.next();
            if (!list1New.contains(s)) {
                list1New.add(s);
            }
        }
        for (int i = 0; i < list1New.size(); i++) {
            System.out.println("去重之後的集合 list1New:" + list1New.get(i));
        }
6433394-187bd1725e9586df.png
實現效果

2)、不建立新集合方式

  List<String> list = new ArrayList<>();
        list.add("北京");
        list.add("天津");
        list.add("上海");
        list.add("河北");
        list.add("河北");
        list.add("河北");
        list.add("河北");
        list.add("山東");
        list.add("山西");
        list.add("山西");
        list.add("山西");

        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (list.get(i).equals(list.get(j))) {
                    list.remove(j);
                    //不新增該步驟,會導致連續資料去重,去不乾淨
                    j--;
                }
            }
        }

        System.out.println("去重後集合: " + list);
6433394-6e22490ab7b7ebef.png
執行結果

在註釋處新增指定的操作,否則導致有重複資料不可去除乾淨。

六、Set 介面那些事兒

1、常識

存入資料 唯一、無序。

2、特有方法

Set 查詢得知,它的方法和 collection 方法完全相同,所以,不太懂或者還有點懵逼,可以看一下前面。

3、效果演示

 Set<String> set = new HashSet<>();
        set.add("北京");
        set.add("天津");
        set.add("上海");
        set.add("河北");
        set.add("山東");
        set.add("山東");

        System.out.println("set集合資料: " + set);

執行效果:


6433394-6b7d506ef07ebda4.png
執行效果

充分驗證了無序與唯一;

七、HashSet 的那些事兒

1、常識

不能保證迭代順序、底層資料結構是雜湊表(雜湊表依賴於雜湊值儲存)、底層新增資料依賴於haseCode()方法和 equals()方法。

2、獨有方法

很高興的告訴你,HashSet 類也沒有自己獨特的方法,那麼,我們來分析一下它是這麼保證唯一性的吧。

3、分析 Set 的實現集合怎麼保證資料唯一性

HashSet<String> set = new HashSet<>();
        set.add("北京");
        set.add("天津");
        set.add("上海");
        set.add("河北");
        set.add("山東");
        set.add("山東");

        for (String s:set){
            System.out.println("set集合資料: " + s);
        }

下面拿起我們的小手,熟練地 跟著add()方法進入原始碼:

 public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

仔細看只是個 map 新增資料啊,然後跟著 map物件 檢視一下:private transient HashMap<E,Object> map; 呦,是個HashMap啊,跟著 map 的值看一下 private static final Object PRESENT = new Object();是個常量,沒大用。那麼 HashMap 就是我們研究的重點了,HashMap 實現了 Map 介面。然後那我們只能看一下 HashMap 的新增元素的方式了,跟著 put()方法,點開原始碼:

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

//------------------------------------------------------

 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

仔細一看 putVal()方法一枝獨秀,對我們很有價值,仔細研究一下:首先,資料進入的時候進行非空的的判斷,待判斷完成之後,進行 hash值的判斷,但是hash 值相等,但是不代表資料一致,繼續進行地址值的判斷,還需要進行 equals()方法的判斷,若判斷結果為 true 則可以將資料進行儲存。

總結:

可以得出一個結論比較事物的相同,首先比較 hash 值、其次是比較地址值、最後是進行 equals 判斷。

這樣導致一個問題,一個類沒有實現 hashCode()方法和 equals()方法, 則需要開發者主動實現這兩個方法。這樣才可以保證唯一性。

八、LinkedHashSet 的那些事

1、常識

元素有序唯一、底層由連結串列保證元素有序、雜湊表保證元素唯一性。

2、特有方法

方法全部來自於實現的介面,所以,請看Set 的相關方法。

3、方法使用

   LinkedHashSet<String> set = new LinkedHashSet<>();
        set.add("北京");
        set.add("天津");
        set.add("上海");
        set.add("河北");
        set.add("山東");
        set.add("山東");

        for (String s:set){
            System.out.println("set集合資料: " + s);
        }
6433394-0e3872ec1a5676ae.png
結果展示

總結:

該集合特點:有序、唯一

九、TreeSet 的那些事兒

1、常識

底層基於 TreeMap 實現、按照元素的自然順序排序(按照某種規則排序),也可根據建立 Set 時提供的 comparator(比較器) 進行排序。

2、特有方法

方法也是和之前的 Set 型別集合相同,沒有特殊方法

3、程式碼演示

  TreeSet<String> set = new TreeSet<>();
        set.add("aaa");
        set.add("ddd");
        set.add("ccc");
        set.add("zzz");
        set.add("kkk");
        set.add("rrr");

        for (String s:set){
            System.out.println("set集合資料: " + s);
        }
6433394-3d4fdc70ff7a1e60.png
執行結果

4、TreeSet 儲存自定義物件 相關問題

1)、自定義物件如何保證排序以及唯一性
原始自定義物件程式碼:

public class Provice {
    private String name;
    private int num;

    public Provice(String name, int num) {
        this.name = name;
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

呼叫程式碼:

  TreeSet<Provice> set = new TreeSet<>();
        set.add(new Provice("北京",1));
        set.add(new Provice("天津",2));
        set.add(new Provice("上海",3));
        set.add(new Provice("重慶",4));
        set.add(new Provice("河北",5));


        for (Provice s:set){
            System.out.println("set集合資料: " + s);
        }

執行結果:


6433394-d763c91fc51880b2.png
執行結果

報錯,報錯原因不能按照某種規則排序,所以改進

兩種解決bug方法:

第一種,外部類實現 Comparable 介面

改進之後的自定義物件程式碼:

public class Province implements Comparable<Province> {
    private String name;
    private int num;

    public Province(String name, int num) {
        this.name = name;
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Province{" +
                "name='" + name + '\'' +
                ", num=" + num +
                '}';
    }


    @Override
    public int compareTo(Province o) {

        //排序的主要條件,按照數字的大小進行排序
        int number = this.num - o.num;
        //次要條件,按照字典順序進行排序
        return number == 0 ? this.name.compareTo(o.name) : number;
    }
}

程式碼呼叫

  TreeSet<Province> set = new TreeSet<>();
        set.add(new Province("北京",1));
        set.add(new Province("天津",2));
        set.add(new Province("上海",10));
        set.add(new Province("山西",10));
        set.add(new Province("重慶",9));
        set.add(new Province("河北",5));


        for (Province s:set){
            System.out.println("set集合資料: " + s);
        }
第二種方法 使用匿名內部類方式

外部類程式碼不變

public class Province {
    private String name;
    private int num;

    public Province(String name, int num) {
        this.name = name;
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Province{" +
                "name='" + name + '\'' +
                ", num=" + num +
                '}';
    }
}

程式碼呼叫:

   TreeSet<Province> set = new TreeSet<>(new Comparator<Province>() {
            @Override
            public int compare(Province o1, Province o2) {

                //排序的主要條件,按照數字的大小進行排序
                int number = o1.getNum() - o2.getNum();
                //次要條件,按照字典順序進行排序
                return number == 0 ? o1.getName().compareTo(o2.getName()) : number;
            }
        });
        set.add(new Province("北京", 1));
        set.add(new Province("天津", 2));
        set.add(new Province("上海", 10));
        set.add(new Province("山西", 10));
        set.add(new Province("重慶", 9));
        set.add(new Province("河北", 5));


        for (Province s : set) {
            System.out.println("set集合資料: " + s);
        }

總結:

當使用無參構造的時,TreeMap 內的元素按照自然順序進行相關排序。

十、Map 集合那些事兒

1、常識

儲存鍵值對元素、鍵值對內鍵是唯一、值可以重複、結構特點只與鍵有關。

Map集合特點:儲存資料成對出現、鍵唯一、值可重複;
Collection集合特點:集合元素單獨出現、Set集合元素唯一、List集合元素可重複;

2、特有方法

1)、新增功能:
V put(K key, V value)新增元素;
2)、刪除功能:
void clear();刪除集合所有元素;
V remove(Object key) ;根據鍵移除資料,並且返回值;
3)、判斷功能:
boolean containsKey(Object key);判斷集合是否包含指定的鍵;
boolean containsValue(Object value);判斷集合是否包含指定的值;
boolean isEmpty();判斷集合是否為空;
4)、獲取功能
Set<Map.Entry<K,V>> entrySet()
v get(Object key)根據鍵 獲取值;
Set<K> keySet();獲取集合中所有鍵的集合;
Collection <v>values獲取集合中所有值的集合;
5)、數量統計
int size()返回鍵值對的數量。

3、方法演示

1)、 put() 方法

程式碼例項:


        Map<String, Integer> map = new HashMap<>();

        map.put("北京", 1);
        map.put("天津", 1);
        map.put("上海", 3);
        map.put("重慶", 4);
        map.put("河北", 5);
        map.put("河北", 6);
        map.put("山東", 7);

        System.out.println("map 內資料:" + map);
6433394-72cb56e777aaa5e3.png
效果展示

總結:

資料無序、key 不可重複、value可重複、 當key重複時,後面的值會覆蓋前面的值。

2、remove()方法
     Map<String, String> map = new HashMap<>();
        map.put("北京", "1");
        map.put("天津", "1");
        map.put("上海", "3");
        map.put("重慶", "4");
        map.put("河北", "5");
        map.put("河北", "6");
        map.put("山東", "7");
        System.out.println("map 內資料:" + map);

        String re = map.remove("北京");

        System.out.println("remove之後的  map 內資料:" + map + " remove之後的返回值 re: " + re);
6433394-72f69a3e28083bee.png
執行結果

可以看出,map 的基本用法大致和 Collection 相同,只是叫法不太一樣。

3、get()方法

        Map<String, String> map = new HashMap<>();
        map.put("北京", "1");
        map.put("天津", "1");
        map.put("上海", "3");
        map.put("重慶", "4");
        map.put("河北", "5");
        map.put("河北", "6");
        map.put("山東", "7");
        System.out.println("map 內資料:" + map);

        String g=map.get("河北");

        System.out.println("get方法呼叫後: "+g);
6433394-3fbdceb4cbf8c8b3.png
get()方法呼叫後效果
4、Set<K> keySet() 與 Collection <v>values 的使用
  Map<String, String> map = new HashMap<>();
        map.put("北京", "1");
        map.put("天津", "1");
        map.put("上海", "3");
        map.put("重慶", "4");
        map.put("河北", "5");
        map.put("山東", "7");
        System.out.println("map 內資料:" + map);

        Set<String> set = map.keySet();

        System.out.println("獲取集合內所有的鍵: " + set);

        Collection<String> values = map.values();

        System.out.println("獲取集合內所有的值: " + values);
6433394-99c17e27a180c409.png
執行結果
5、Set<Map.Entry<K,V>> entrySet() 的相關

關於這個的使用,我們還是從一個小例子引出吧
需求:遍歷集合,取出所有的鍵值對

1)、方案一 分批獲取

        Map<String, String> map = new HashMap<>();
        map.put("北京", "1");
        map.put("天津", "1");
        map.put("上海", "3");
        map.put("重慶", "4");
        map.put("河北", "5");
        map.put("山東", "7");
        System.out.println("map 內資料:" + map);

        Set<String> set = map.keySet();

        for (String key : set) {
            String value = map.get(key);
            System.out.println("鍵值對 ---鍵:" + key + "  鍵值對---值:" + value);
        }
6433394-fdd60925bdb32bd0.png
執行結果
方案二: 成對獲取

        Map<String, String> map = new HashMap<>();
        map.put("北京", "1");
        map.put("天津", "1");
        map.put("上海", "3");
        map.put("重慶", "4");
        map.put("河北", "5");
        map.put("山東", "7");
        System.out.println("map 內資料:" + map);

        
        Set<Map.Entry<String, String>> set = map.entrySet();

        //Map.Entry<String, String> 為介面 ,但是 m 肯定為子類型別,可以取出 使用。
        for (Map.Entry<String, String> m : set) {
            System.out.println("鍵值對---鍵:" + m.getKey() + "  鍵值對---值:" + m.getValue());
        }
6433394-15f045edfcc0d009.png
執行結果

兩個方案比較:第一種方案,是在遍歷的過程中先取到集合的鍵,然後根據鍵去獲取值,屬於分、分、總。類似於 1+1=2 的 過程。
第二種方法,是直接遍歷集合 “鍵值對” 的物件,然後通過該物件 直接取出 鍵和值。

十一、HashMap 的那些事兒

可以說 HashMap 只是 Map 的 的簡簡單單的實現,並沒有什麼特別的。

注意一點:

當使用自定義類來做鍵時,需要在自定義類內重寫 equals() 方法 ,否則會導致出現重複的鍵值對。

十二、LinkedHashMap 的那些兒

1、常識

LinkedHashMap 是 HashMap 的子類、鍵唯一、有序(儲存和取出順序一致)

2、程式碼演示

   LinkedHashMap<String, String> map = new LinkedHashMap<>();
        map.put("北京", "1");
        map.put("天津", "1");
        map.put("上海", "3");
        map.put("重慶", "4");
        map.put("河北", "5");
        map.put("山東", "7");
        System.out.println("map 內資料:" + map);
        
        Set<Map.Entry<String, String>> set = map.entrySet();

        for (Map.Entry<String, String> m : set) {
            System.out.println("鍵值對---鍵:" + m.getKey() + "  鍵值對---值:" + m.getValue());
        }
6433394-0aa03e1891693c33.png
執行效果

可以看出,存入的順序和輸出的順序是一致的。

十三、TreeMap 的那些事兒

1、鍵是紅黑樹結構,可以保證鍵的排序和唯一性。類似於 TreeSet 。

2、方法使用

TreeMap 沒有什麼特別的方法,我們來關注一下它的排序規律吧

1)、基本型別資料

        TreeMap<String, String> map = new TreeMap<>();
        map.put("beijing", "1");
        map.put("tianjin", "1");
        map.put("shanghai", "3");
        map.put("chongqing", "4");
        map.put("hebei", "5");
        map.put("shandong", "7");
        System.out.println("map 內資料:" + map);
6433394-b3b28911410ac3cc.png
實現效果
2)、自定義物件資料

自定義物件的

public class Province {
    private String name;
    private int num;

    public Province(String name, int num) {
        this.name = name;
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Province{" +
                "name='" + name + '\'' +
                ", num=" + num +
                '}';
    }
}

呼叫程式碼

  TreeMap<Province, String> map = new TreeMap<>();

        Province province1=new Province("北京",1);
        Province province2=new Province("上海",2);
        Province province3=new Province("天津",3);
        Province province4=new Province("深圳",4);
        Province province5=new Province("重慶",5);
        Province province6=new Province("廣州",6);


        map.put(province1, "1");
        map.put(province2, "1");
        map.put(province3, "3");
        map.put(province4, "4");
        map.put(province5, "5");
        map.put(province6, "7");
        System.out.println("map 內資料:" + map);

笑嘻嘻一執行,心裡馬上MMP;


6433394-18222ef4c1bd8862.png
執行效果

產生問題原因是:我們並沒有指定排序順序,下面開始解決問題

類似於 TreeSet


        TreeMap<Province, String> map = new TreeMap<>(new Comparator<Province>() {
            @Override
            public int compare(Province o1, Province o2) {
                //主要排序條件
                int num = o1.getNum() - o2.getNum();
                //次要排序規則
                int name = num == 0 ? o1.getName().compareTo(o2.getName()) : num;
                return name;
            }
        });

        Province province1 = new Province("北京", 1);
        Province province4 = new Province("深圳", 4);
        Province province6 = new Province("廣州", 6);
        Province province5 = new Province("重慶", 5);
        Province province2 = new Province("上海", 2);
        Province province3 = new Province("天津", 3);

        map.put(province1, "1");
        map.put(province2, "1");
        map.put(province3, "3");
        map.put(province4, "4");
        map.put(province5, "5");
        map.put(province6, "7");
        System.out.println("map 內資料:" + map);
6433394-67d54a324ea8c0e7.png
執行結果

十四、集合相關的其它問題

1、Hashtable 與 HashMap 的區別

Hashtable:執行緒安全、效率低、不允許 null 鍵、不允許 null 值
HashMap :執行緒不安全、效率高、允許 null 鍵、允許 null 值

2、Collections 的那些事兒

1)、常識

針對集合操作的工具類、均是靜態方法;
與 Collection 的區別,Collections 是針對集合操作的工具類類、Collection 是單列集合的頂層介面

2)、應該知道的方法

public static <T> void sort(List<T> list);排序(預設情況下自然排序);
public static <T> void binarySearch(List<?> list,T key) 二分查詢;
public static <T> T max (Collection<?> coll)最大值;
public static void reverse(List<?> list)反轉;
public static void shuffle(List <?> list)隨機置換;

相關文章