8-集合

我丶秦始皇丶打錢發表於2020-10-02

集合

集合的作用: 理論上儲存多個不同型別的元素資料。(實際開發中 儲存相同型別的元素)

集合元素型別: 都是引用型別。

所有的集合:(儲存,遍歷)

集合儲存資料: 資料從哪裡來的??---->資料庫查詢來的

集合體系

分為2類: Collection Map

Collection 儲存單值元素 value

Map: 儲存一組元素 key----value

在這裡插入圖片描述

Collection介面

<>: 泛型的標誌 可以修飾類(泛型類) 修飾介面(泛型介面)

: 引數化型別 (限定集合元素的資料型別)----> 集合元素型別單一 A-Z //< >裡放 A-Z的大寫字母都可以

Collection的元素本身就是無序的(沒有索引位置)

tips:一般在建立物件時,將未知的型別確定具體的型別。當沒有指定泛型時,預設型別為Object型別。

Collection是所有單列集合的父介面,因此在Collection中定義了單列集合(List和Set)通用的一些方法,這些方法可用於操作所有的單列集合。方法如下:

增刪:
 *boolean add(E e)  將元素資料新增集合物件中             
  boolean addAll(Collection<? extends E> c)  
 
 *boolean remove(Object o)   根據元素資料刪除
  boolean removeAll(Collection<?> c)
  default boolean removeIf(Predicate<? super E> filter) 刪除多個符合條件的元素 lamda
 *void clear()  刪除/清空集合裡面所有的元素
 
遍歷:
   //增強for迴圈
default void forEach(Consumer<? super T> action)  遍歷集合元素 lamda
Iterator<T> iterator() 獲得集合物件的迭代器物件(遍歷集合元素) --->集合的所有的元素都在迭代器物件
   Iterator介面的常用方法如下:
   1. boolean hasNext()  判斷游標後面是否有更多的元素需要遍歷
   2. E next()  獲得游標之後的元素
   3. default void remove()  刪除集合元素
    
判斷:
*boolean contains(Object o)  判斷集合物件中是否包含一個元素
 boolean containsAll(Collection<?> c)
*boolean isEmpty()  集合是否是空

*int size()  獲得集合元素個數
    
*`public Object[] toArray()`: 把集合中的元素,儲存到陣列中。    
 
default Stream<E> parallelStream()  獲得集合物件的Stream例項--->集合可以執行並行化操作 lamda
public class Demo1Collection {
    public static void main(String[] args) {
		// 建立集合物件 
    	// 使用多型形式
    	//建立物件的時候   new的必須是實現類
    	Collection<String> coll = new ArrayList<String>();                   
    	// 使用方法
    	// 新增功能  boolean  add(String s)
    	coll.add("小李廣");
    	coll.add("掃地僧");
    	coll.add("石破天");
    	System.out.println(coll);

    	// boolean contains(E e) 判斷o是否在集合中存在
    	System.out.println("判斷  掃地僧 是否在集合中"+coll.contains("掃地僧"));

    	//boolean remove(E e) 刪除在集合中的o元素
    	System.out.println("刪除石破天:"+coll.remove("石破天"));
    	System.out.println("操作之後集合中元素:"+coll);
    	
    	// size() 集合中有幾個元素
		System.out.println("集合中有"+coll.size()+"個元素");

		// Object[] toArray()轉換成一個Object陣列
    	Object[] objects = coll.toArray();
    	// 遍歷陣列
    	for (int i = 0; i < objects.length; i++) {
			System.out.println(objects[i]);
		}

		// void  clear() 清空集合
		coll.clear();
		System.out.println("集合中內容為:"+coll);
		// boolean  isEmpty()  判斷是否為空
		System.out.println(coll.isEmpty());  	
	}
}




//如何使用Iterator迭代集合中元素:
public class IteratorDemo {
  	public static void main(String[] args) {
        // 使用多型方式 建立物件
        Collection<String> coll = new ArrayList<String>();

        // 新增元素到集合
        coll.add("串串星人");
        coll.add("吐槽星人");
        coll.add("汪星人");
        //遍歷
        //使用迭代器 遍歷   每個集合物件都有自己的迭代器
        Iterator<String> it = coll.iterator();
        //  泛型指的是 迭代出 元素的資料型別
        while(it.hasNext()){ //判斷是否有迭代元素
            String s = it.next();//獲取迭代出的元素
            System.out.println(s);
        }
        
        //使用增強for遍歷
    	for(String s :coll){//接收變數s代表 代表被遍歷到的集合元素
    		System.out.println(s);
    	}
	}
  	}
}
//tips::在進行集合元素取出時,如果集合中已經沒有元素了,還繼續使用迭代器的next方法
//將會發生java.util.NoSuchElementException沒有集合元素的錯誤。
List介面
元素是否有序(索引)元素是否可重複
List有序(即元素的存入順序和取出順序一致)可重複
Set無序元素唯一
獨有的功能方法:
  void add(int index, E element)  指定索引位置新增元素資料
  E get(int index) 獲得指定索引位置的元素資料  0--size()-1
  ListIterator<E> listIterator()  獲得集合迭代器物件
  E remove(int index)  刪除指定索引元素資料並獲得舊值
  E set(int index, E element)  修改指定索引的元素並返回修改之前的資料
  List<E> subList(int fromIndex, int toIndex)  對擷取陣列增加,刪除,修改會高度還原到原陣列上.
  Object[] toArray()  
  <T> T[] toArray(T[] a)(推薦)  
public class ListDemo {
    public static void main(String[] args) {
		// 建立List集合物件
    	List<String> list = new ArrayList<String>();
    	
    	// 往 尾部新增 指定元素
    	list.add("圖圖");
    	list.add("小美");
    	list.add("不高興");
    	
    	System.out.println(list);
    	// add(int index,String s) 往指定位置新增
    	list.add(1,"沒頭腦");
    	
    	System.out.println(list);
    	// String remove(int index) 刪除指定位置元素  返回被刪除元素
    	// 刪除索引位置為2的元素 
    	System.out.println("刪除索引位置為2的元素");
    	System.out.println(list.remove(2));
    	
    	System.out.println(list);
    	
    	// String set(int index,String s)
    	// 在指定位置 進行 元素替代(改) 
    	// 修改指定位置元素
    	list.set(0, "三毛");
    	System.out.println(list);
    	
    	// String get(int index)  獲取指定位置元素
    	
    	// 跟size() 方法一起用  來 遍歷的 
    	for(int i = 0;i<list.size();i++){
    		System.out.println(list.get(i));
    	}
    	//還可以使用增強for
    	for (String string : list) {
			System.out.println(string);
		}  	
	}
}
底層資料結構效率執行緒安全
* ArrayList動態陣列查詢最快不安全
LInkedList雙向連結串列刪除 新增效率最快不安全
Vector動態陣列都慢安全

連結串列:

元素資料 引用(記憶體地址值)—(上一個元素的引用 下一個元素的引用)

單向連結串列: 元素資料 下一個元素的引用

雙向連結串列: 元素資料 上一個元素的引用 下一個元素的引用

* ArrayList
常用的構造:
   ArrayList() 構造一個初始容量為十的空列表。(1.5擴容) 
   ArrayList(Collection<? extends E> c) 
   ArrayList(int initialCapacity) //10
       initialCapacity: (儲存的元素個數/負載因子+1)
     //建立List集合物件
        ArrayList<Integer> list = new ArrayList<>();//初始化容量10
        //1.新增元素
        list.add(100);
        list.add(200);
        list.add(200);
        list.add(300);
        list.add(2);
        list.add(3);
        list.add(0,1);// >=0 <=size
        System.out.println(list);
        //2.獲得
        Integer num = list.get(0);//elementData[index]
        System.out.println(num);
        //3.刪除
        System.out.println(list.remove(1));
        System.out.println(list);
        //4.修改
        System.out.println(list.set(0, 11));
        System.out.println(list);//[11, 200, 200, 300, 2, 3]
        List<Integer> list1 = list.subList(0, 3);//包頭不包尾
        System.out.println(list1);
        //對擷取陣列增加  刪除  修改 會  高度還原到原陣列上的
        System.out.println("list1:"+list1);
        System.out.println("list:"+list);
//        list1.remove(0);
//        list.add(0,12);//modCount==size  failfast


        //集合 轉換陣列
        // Object[] toArray() 
        Object[] toArray = list.toArray();
        System.out.println("toArray:"+Arrays.toString(toArray));
        for (Object o : toArray) {              //這樣轉換的陣列 要想遍歷Integer的話  還需要強轉
            //手動強制
            Integer num1 = (Integer) o;
        }
        
        //<T> T[] toArray(T[] a)(推薦) 
		Integer[] integers =  list.toArray(new Integer[0]);
        System.out.println("toArray:"+Arrays.toString(integers));

遍歷

private static void demo2() {
        List<String> list = new ArrayList<>(10);
        //遍歷
        list.add("abc");
        list.add("abc1");
        list.add("abc2");
        list.add("abc3");
        list.add("abc4");
        list.add("abc");

        //1.普通迴圈
//        for (int i = 0,size = list.size(); i < size; i++) {
//            System.out.println(list.get(i));
//        }

        //2.增強for
//        for (String s : list) {
//            System.out.println(s);
//        }


        //3.迭代器
//        Iterator<String> iterator = list.iterator();
//        while(iterator.hasNext()){
//            String next = iterator.next();
//            System.out.println(next);
//        }

        //4.listIterator
//        ListIterator<String> listIterator = list.listIterator();
//        while (listIterator.hasNext()) {
//            String next = listIterator.next();
//            System.out.println(next);
//
//        }

        //5.forEach
        list.forEach((String str)->{
            System.out.println(str);
        });
    }

遍歷修改

   private static void demo3() {
        ArrayList<String> list = new ArrayList<>(10);
        //遍歷
        list.add("abc");
        list.add("abc1");
        list.add("abc2");
        list.add("abc3");
        list.add("abc4");
        list.add("abc");
        System.out.println("刪除之前:"+list);
        //刪除元素都是abc
//        list.forEach((String str)->{
//           if("abc".equals(str)){
//               //找到了元素  刪除
//               list.add("123");                    遍歷期間forEach刪除元素會報錯 修改一般不會 可能會出現
//           }
//        });

//        for (int i = 0; i < list.size(); i++) {         for迴圈都可以
//            if("abc".equals(list.get(i))
//               list.remove("abc");
//           }
//        }
//        Iterator<String> iterator = list.iterator();        ***
//        System.out.println(iterator);                   //java.util.ArrayList$Itr@4141d797
//        while(iterator.hasNext()){
//            String next = iterator.next();
//            if("abc".equals(next)){
//               iterator.remove();                     迭代器不能用list的remove  只能用iterator.remove();
//           }
//        }
//        System.out.println("刪除之後:"+list);// Exception in thread "main" java.util.ConcurrentModificationException

//        for (String s : list) {                       //迭代器實現的
//            if("abc3".equals(s)){
//               //找到了元素  刪除
//              list.remove(s);                          //只能刪倒數第二個元素
//           }
//        }
        Iterator<String> iterator = list.iterator();
        for(;iterator.hasNext();){
            String next = iterator.next();//cursor
            if("abc3".equals(next)){
                //找到了元素  刪除
                list.remove(next);                       //只能刪倒數第二個元素
            }
        }
        System.out.println("刪除之後:"+list);
    }
LinkedList
LinkedList   集合資料儲存的結構是連結串列結構。方便元素新增、刪除的集合。
理論上可以儲存無數個元素。    
 佇列: 排隊---> 先進先出
 棧: fifo 先進後出
 LinkedList() 
    
 
LinkedList提供了大量首尾操作的方法。這些方法我們作為了解即可:

* `public void addFirst(E e)`:將指定元素插入此列表的開頭。
* `public void addLast(E e)`:將指定元素新增到此列表的結尾。
* `public E getFirst()`:返回此列表的第一個元素。
* `public E getLast()`:返回此列表的最後一個元素。
* `public E removeFirst()`:移除並返回此列表的第一個元素。
* `public E removeLast()`:移除並返回此列表的最後一個元素。
* `public E pop()`:從此列表所表示的堆疊處彈出一個元素。
* `public void push(E e)`:將元素推入此列表所表示的堆疊。
* `public boolean isEmpty()`:如果列表不包含元素,則返回true。

LinkedList是List的子類,List中的方法LinkedList都是可以使用,這裡就不做詳細介紹,
我們只需要瞭解LinkedList的特有方法即可。在開發時,LinkedList集合也可以作為堆疊,佇列的結構使用。(瞭解即可)    
public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<String> link = new LinkedList<String>();
        //新增元素
        link.addFirst("abc1");
        link.addFirst("abc2");
        link.addFirst("abc3");
        System.out.println(link);
        // 獲取元素
        System.out.println(link.getFirst());
        System.out.println(link.getLast());
        // 刪除元素
        System.out.println(link.removeFirst());
        System.out.println(link.removeLast());

        while (!link.isEmpty()) { //判斷集合是否為空
            System.out.println(link.pop()); //彈出集合中的棧頂元素
        }

        System.out.println(link);
    }
}
Vector
Vector() 
Vector(int initialCapacity)  //10
Set介面

Set集合的元素是無序的(index) 元素唯一的

tips:Set集合取出元素的方式可以採用:迭代器、增強for

資料結構執行緒安全元素是否可以為null
HashSet雜湊表(HashMap)不安全可以為null
LinkedHashSet連結串列+雜湊表不安全可以為null
TreeSet紅黑樹不安全不能為null
* HashSet
此類實現Set介面,由雜湊表(實際為HashMap例項)支援. 元素無序,(順序)
 HashSet() 構造一個新的空集合; 背景HashMap例項具有預設初始容量(16)和負載因子(0.75)。    
 HashSet(int initialCapacity)  (儲存的元素個數/負載因子)+1 
 HashSet(Collection<? extends E> c) (List集合去重)
public class HashSetDemo {

    public static void main(String[] args) {
        demo1();
    }

    private static void demo1() {
        HashSet<Integer> hashSet = new HashSet<>();
        //新增元素
        System.out.println(hashSet.add(100));//true
        System.out.println(hashSet.add(100));//false
        System.out.println(hashSet.add(1));
        System.out.println(hashSet.add(10));
        System.out.println(hashSet.add(null));
        System.out.println(hashSet.add(10));

        System.out.println(hashSet.toString());

        //其它的方法與Collection一模一樣

       
        //3種遍歷方法

        for (Integer integer : hashSet) {
            System.out.println(integer);
        }
        System.out.println("------------------------");
        
        Iterator<Integer> iterator = hashSet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("------------------------");

        hashSet.forEach((num)->{
            System.out.println(num);
        });
    }
}
  • HashSet儲存自定義型別元素

給HashSet中存放自定義型別元素時,需要重寫物件中的hashCode和equals方法,建立自己的比較方式,才能保證HashSet集合中的物件唯一

建立自定義Student類

/*
    HashSet儲存自定義型別元素

    set集合報錯元素唯一:
        儲存的元素(String,Integer,...Student,Person...),必須重寫hashCode方法和equals方法

    要求:
        同名同年齡的人,視為同一個人,只能儲存一次
 */
public class HashSetDemo2 {
    public static void main(String[] args) {
        //建立集合物件   該集合中儲存 Student型別物件
        HashSet<Student> stuSet = new HashSet<Student>();
        //儲存 
        Student stu = new Student("于謙", 43);
        stuSet.add(stu);
        stuSet.add(new Student("郭德綱", 44));
        stuSet.add(new Student("于謙", 43));
        stuSet.add(new Student("郭麒麟", 23));
        stuSet.add(stu);                                 //不重寫 相同名字跟年齡的都會存進去

        for (Student stu2 : stuSet) {
            System.out.println(stu2);
        }
    }
}
執行結果:
Student [name=郭德綱, age=44]
Student [name=于謙, age=43]
Student [name=郭麒麟, age=23]
public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        Student student = (Student) o;
        return age == student.age &&
               Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
LinkedHashSet

我們知道HashSet保證元素唯一,可是元素存放進去是沒有順序的,那麼我們要保證有序,怎麼辦呢?

在HashSet下面有一個子類java.util.LinkedHashSet,它是連結串列和雜湊表組合的一個資料儲存結構。

演示程式碼如下:

雜湊表和連結串列實現了Set介面,具有可預測的迭代次序(插入順序與遍歷順序是一致的)
    
LinkedHashSet() 構造一個具有預設初始容量(16)和負載因子(0.75)的新的,空的連結雜湊集
LinkedHashSet(int initialCapacity) 
 構造一個具有指定初始容量和預設負載因子(0.75)的新的,空的連結雜湊集


public class LinkedHashSetDemo {
	public static void main(String[] args) {
		Set<String> set = new LinkedHashSet<String>();
		set.add("bbb");
		set.add("aaa");
		set.add("abc");
		set.add("bbc");
        Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
結果:
  bbb
  aaa
  abc
  bbc
TreeSet
基於TreeMap。 元素都是有序的(會按照自然順序排列)--->要求元素型別必須有排序規則(Comparable) 
    
TreeSet() 
TreeSet(Comparator<? super E> comparator) 外部比較器(排序規則)    
    
public class TreeSetDemo {

    public static void main(String[] args) {
        TreeSet<Integer> treeSet = new TreeSet<>();//預設是按照升序排列的
        treeSet.add(100);
        treeSet.add(1);
        treeSet.add(2);
        System.out.println(treeSet);
    }
}

Map<K,V>介面

儲存一組元素。 有key 有value K V 都是map集合的引數化型別。

將key對映到value上。 可以根據key獲得value值

map集合的key是唯一的。value可以重複。

底層資料結構執行緒安全k/v是否可以為null
HashMap<K,V>雜湊表都可以為null
LinkedHashMap<K,V>雜湊表+連結串列都可以為null
TreeMap<K,V>紅黑樹k不能為null V:可以
HashTable<K,V>雜湊表安全(悲觀鎖)K/V都不能為null
ConcurrentHashMap<K,V>鎖分段技術/CAS(樂觀鎖)安全K/V都不能為null
static interface  Map.Entry<K,V>  維護map集合裡面每組元素的
    
void clear()  清空map集合所有的元素
boolean containsKey(Object key)  判斷map集合是否包含指定的key
boolean containsValue(Object value)  判斷map集合是否包含指定的value

    
V get(Object key)  根據key獲得v
default V getOrDefault(Object key, V defaultValue)  

boolean isEmpty()  
V put(K key, V value)  新增一組元素
V remove(Object key)  刪除
default boolean remove(Object key, Object value)  
 
default V replace(K key, V value) 
default boolean replace(K key, V oldValue, V newValue)  
int size()  

通過檢視Map介面描述,看到Map有多個子類,這裡我們主要講解常用的HashMap集合、LinkedHashMap集合。

  • HashMap<K,V>:儲存資料採用的雜湊表結構,元素的存取順序不能保證一致。由於要保證鍵的唯一、不重複,需要重寫鍵的hashCode()方法、equals()方法。
  • LinkedHashMap<K,V>:HashMap下有個子類LinkedHashMap,儲存資料採用的雜湊表結構+連結串列結構。通過連結串列結構可以保證元素的存取順序一致;通過雜湊表結構可以保證的鍵的唯一、不重複,需要重寫鍵的hashCode()方法、equals()方法。

tips:Map介面中的集合都有兩個泛型變數<K,V>,在使用時,要為兩個泛型變數賦予資料型別。兩個泛型變數<K,V>的資料型別可以相同,也可以不同。

* HashMap<K,v>
HashMap(int initialCapacity) 


private static void demo1() {

        //在正常的開發中,map的key的資料型別:String居多====> json串--->屬性名稱(全部都是字串): 屬性值
        HashMap<Integer, String> hashMap = new HashMap<>(16);

        //1.儲存元素
        hashMap.put(1, "a");
        hashMap.put(10, "b");
        hashMap.put(100, "c");
        hashMap.put(1, "ccccc");
        System.out.println(hashMap.size());//  map的key重複的時候  value會被覆蓋。

        //2.獲取map元素
        String s = hashMap.get(1);
        System.out.println(s);

        //3.刪除
//        System.out.println(hashMap.remove(1));//ccccc
//        System.out.println(hashMap.remove(1,"ccccc"));

        //4.修改
        System.out.println(hashMap.replace(1, "10"));

        //5.判斷
        System.out.println(hashMap.containsKey(1));
        System.out.println(hashMap.containsValue("10"));
        System.out.println(hashMap);
    }

  • 遍歷
Set<Map.Entry<K,V>> entrySet() 
    
遍歷map集合的方法(獲得map集合的每一組k/V轉換成一個個entry物件  並儲存到set集合中)   
    default void forEach(BiConsumer<? super K,? super V> action)   遍歷map集合
    Set<K> keySet()  遍歷map集合方法(獲得map集合裡面所有的key 並把key儲存到set)    
    Collection<V> values() 獲得map集合的所有的v
黑馬:
Map集合遍歷鍵找值方式   
鍵找值方式:即通過元素中的鍵,獲取鍵所對應的值

分析步驟:
1. 獲取Map中所有的鍵,由於鍵是唯一的,所以返回一個Set集合儲存所有的鍵。方法提示:`keyset()`
2. 遍歷鍵的Set集合,得到每一個鍵。
3. 根據鍵,獲取鍵所對應的值。方法提示:`get(K key)`    
    
public class MapDemo01 {
    public static void main(String[] args) {
        //建立Map集合物件 
        HashMap<String, String> map = new HashMap<String,String>();
        //新增元素到集合 
        map.put("胡歌", "霍建華");
        map.put("郭德綱", "于謙");
        map.put("薛之謙", "大張偉");

        //獲取所有的鍵  獲取鍵集
        Set<String> keys = map.keySet();
        // 遍歷鍵集 得到 每一個鍵
        for (String key : keys) {
          	//key  就是鍵
            //獲取對應值
            String value = map.get(key);
            System.out.println(key+"的CP是:"+value);
        }  
    }
}   
黑馬: 
Map集合遍歷鍵值對方式
鍵值對方式:即通過集合中每個鍵值對(Entry)物件,獲取鍵值對(Entry)物件中的鍵與值。
    
操作步驟與圖解:
1.  獲取Map集合中,所有的鍵值對(Entry)物件,以Set集合形式返回。方法提示:entrySet()。
2.  遍歷包含鍵值對(Entry)物件的Set集合,得到每一個鍵值對(Entry)物件。
3.  通過鍵值對(Entry)物件,獲取Entry物件中的鍵與值。  方法提示:getkey() getValue() 
     
     
public class MapDemo02 {
    public static void main(String[] args) {
        // 建立Map集合物件 
        HashMap<String, String> map = new HashMap<String,String>();
        // 新增元素到集合 
        map.put("胡歌", "霍建華");
        map.put("郭德綱", "于謙");
        map.put("薛之謙", "大張偉");

        // 獲取 所有的 entry物件  entrySet
        Set<Entry<String,String>> entrySet = map.entrySet();

        // 遍歷得到每一個entry物件
        for (Entry<String, String> entry : entrySet) {
           	// 解析 
            String key = entry.getKey();
            String value = entry.getValue();  
            System.out.println(key+"的CP是:"+value);
        }
    }
}            
private static void demo2() {

        HashMap<Integer, String> hashMap = new HashMap<>(16);
        hashMap.put(1, "a");
        hashMap.put(10, "b");
        hashMap.put(100, "c");
        hashMap.put(0, "c");
        hashMap.put(null, "ccccc");
        hashMap.put(2, null);

        //遍歷
        //forEach遍歷 需要重寫方法
        hashMap.forEach(new BiConsumer<Integer, String>() {
            @Override
            public void accept(Integer key, String value) {
                System.out.println("key:"+key+",value:"+value);
            }
        });
        //forEach遍歷  -----lambda 簡化方式
        hashMap.forEach((key, value)->{
            System.out.println("key:"+key+",value:"+value);
        });

        //jdk1.8之前-
//        hashMap.entrySet();  entry:鍵值對 推薦
        Set<Map.Entry<Integer, String>> entries = hashMap.entrySet();//等同遍歷set集合了
        Iterator<Map.Entry<Integer, String>> iterator = entries.iterator();
        while(iterator.hasNext()){
            Map.Entry<Integer, String> entry = iterator.next();// k  v
            System.out.println("key:"+entry.getKey()+",value:"+entry.getValue());
        }

        //keySet()
        Set<Integer> keySet = hashMap.keySet();//map的key
        keySet.forEach(key->{
            System.out.println("key:"+key+",value:"+hashMap.get(key));
        });

        //Collection<V> values()    java.util.HashMap$Values
        Collection<String> values = hashMap.values();
        System.out.println(values);
    }
LinkedHashMap

我們知道HashMap保證成對元素唯一,並且查詢速度很快,可是成對元素存放進去是沒有順序的,那麼我們要保證有序,還要速度快怎麼辦呢?

在HashMap下面有一個子類LinkedHashMap,它是連結串列和雜湊表組合的一個資料儲存結構。

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
        map.put("鄧超", "孫儷");
        map.put("李晨", "范冰冰");
        map.put("劉德華", "朱麗倩");
        Set<Entry<String, String>> entrySet = map.entrySet();
        for (Entry<String, String> entry : entrySet) {
            System.out.println(entry.getKey() + "  " + entry.getValue());
        }
    }
}

結果:
鄧超  孫儷
李晨  范冰冰
劉德華  朱麗倩
TreeMap
TreeMap(Comparator<? super K> comparator) 
TreeMap()   
 private static void demo4() {
        TreeMap<Integer, String> map = new TreeMap<>();
        //無參構造建立物件  在底層comparator = null; 自定義比較器(自定義的排序規則)
        map.put(1, "a");
        map.put(10, "b");
        map.put(100, "c");
        map.put(1, "c");
        map.put(2, null);

        System.out.println(map);

    }

Collections 類

常用功能
  • java.utils.Collections是集合工具類,用來對集合進行操作。部分方法如下:
  • public static <T> boolean addAll(Collection<T> c, T... elements):往集合中新增一些元素。

  • public static void shuffle(List<?> list) 打亂順序:打亂集合順序。

  • public static <T> void sort(List<T> list):將集合中元素按照預設規則排序。

  • public static <T> void sort(List<T> list,Comparator<? super T> ):將集合中元素按照指定規則排序。

  • static List synchronizedList(List list) :將集合變成執行緒安全的方法

    static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)

程式碼演示:

  private static void demo2() {
        List<Integer> list = new ArrayList<>(10);
        Collections.addAll(list, 2, 10, 30, 1, 101, 100);   
        System.out.println("排序之前:" + list);
        Collections.sort(list);// 要求集合元素型別必須實現Comparable介面
        //預設按照升序排列  //預設按照集合元素型別規定的額排序規則   Integer.compareTo() 
        System.out.println("排序之後:" + list);
    }
        //[2,10,30,1,101,100]
        //[1,2,10,30,100,101]

    private static List<String> myList;//執行緒安全

    private static void demo1() {
        List<String> list = new ArrayList<>(10);
        Collections.addAll(list, "abc", "11", "123", "a", "b");
        System.out.println(list);
        //將執行緒不安全的例項轉換成執行緒安全的物件
        myList = Collections.synchronizedList(list);

    }
}

排序

  • 一種是比較死板的採用java.lang.Comparable介面去實現

  • 一種是靈活的當我需要做排序的時候在去選擇的java.util.Comparator介面完成

//public static <T> void sort(List<T> list):將集合中元素按照預設規則排序
//Comparable`介面去實現
public class CollectionsDemo2 {
    public static void main(String[] args) {
        ArrayList<String>  list = new ArrayList<String>();
        list.add("cba");
        list.add("aba");
        list.add("sba");
        list.add("nba");
        //排序方法
        Collections.sort(list);
        System.out.println(list);
    }
}
//[aba, cba, nba, sba]



//當你想改變預設的排序方式
// public int compare(String o1, String o2):比較其兩個引數的順序
//Comparator`介面完成
public class CollectionsDemo3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("cba");
        list.add("aba");
        list.add("sba");
        list.add("nba");
        //排序方法  按照第一個單詞的降序
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.charAt(0) - o1.charAt(0);
            }
        });
        System.out.println(list);
    }
}
//[sba, nba, cba, aba]

Comparable和Comparator兩個介面的區別

Comparable:強行對實現它的每個類的物件進行整體排序。這種排序被稱為類的自然排序,類的compareTo方法被稱為它的自然比較方法。只能在類中實現compareTo()一次,不能經常修改類的程式碼實現自己想要的排序。實現此介面的物件列表(和陣列)可以通過Collections.sort(和Arrays.sort)進行自動排序,物件可以用作有序對映中的鍵或有序集合中的元素,無需指定比較器。

Comparator強行對某個物件進行整體排序。可以將Comparator 傳遞給sort方法(如Collections.sort或 Arrays.sort),從而允許在排序順序上實現精確控制。還可以使用Comparator來控制某些資料結構(如有序set或有序對映)的順序,或者為那些沒有自然順序的物件collection提供排序。

List

Comparable<T>: java.lang.* 內部比較器 compareTo()

Comparable
 private static void demo3() {
        //List集合元素可以重複 list集合的元素型別沒有必要重寫equals和hashcode
        List<User> userList = new ArrayList<>(10);
        Collections.addAll(userList,
                new User(1, "jim1"),
                new User(1, "jim1"),
                new User(8, "jim3"),
                new User(8, "jim4"));

        System.out.println("排序之前:" + userList);
        Collections.sort(userList);
        System.out.println("排序之後:" + userList);
    }

@Setter
@Getter
@AllArgsConstructor
@ToString
public class User implements Comparable<User> {
    private Integer id;
    private String name;

    @Override
    public int compareTo(User user) {
        Objects.requireNonNull(user);
        if (this == user) {
            return 0;//代表2個物件是相等的
        }
        //比較規則  看屬性 根據id升序排列
        //id一致  name也參與比較(降序)
        int result = this.id.compareTo(user.id);
        if (result == 0) {
            result = user.name.compareTo(this.name);
        }
        return result;//0 -1 1
    }
}
Comparator
@Setter
@Getter
@AllArgsConstructor
@ToString
public class User{
    private Integer id;
    private String name;
}

private static void demo4() {
        List<User> userList = new ArrayList<>(10);
        Collections.addAll(userList,
                new User(1, "jim1"),
                new User(10, "jim11"),
                new User(8, "jim3"),
                new User(7, "jim4"));

        System.out.println("排序之前:" + userList);


        //TreeSet  TreeMap 有參構造  Comparator  自定義外部比較器規則
        Collections.sort(userList, new Comparator<User>() {
            @Override
            public int compare(User user1, User user2) {
                int result = user1.getId().compareTo(user2.getId());
                if(result==0){
                    result = user1.getName().compareTo(user2.getName());
                }
                return result;
            }
        });
    
        //lambada 簡化格式
             Collections.sort(userList, (user1, user2) -> {
            int result = user1.getId().compareTo(user2.getId());
            if (result == 0) {
                result = user1.getName().compareTo(user2.getName());
            }
            return result;
        });
        //
        System.out.println("排序之後:" + userList);

    }
set (集合元素是唯一)
 HashSet/LinkedHashSet   無法排序
 TreeSet 排序 
 private static void demo4() {
        //分支
        TreeSet<User> treeSet = new TreeSet<>();
        treeSet.add(new User(1, "jim7"));
        treeSet.add(new User(1, "jim1"));
        treeSet.add(new User(8, "jim7"));
        treeSet.add(new User(8, "jim4"));
        System.out.println(treeSet);
    }
public class User implements Comparable<User> {
//public class User{
    private Integer id;
    private String name;

    @Override
    public int compareTo(User user) {
        Objects.requireNonNull(user);
        if (this == user) {
            return 0;//代表2個物件是相等的
        }
        return user.name.compareTo(this.name);//0 -1 1
    }
}

//lambda簡寫
 private static void demo5() {
        TreeSet<User> treeSet = new TreeSet<>((User o1, User o2)->{
            return o2.getName().compareTo(o1.getName());
        });
        treeSet.add(new User(1, "jim7"));
        treeSet.add(new User(1, "jim1"));
        treeSet.add(new User(8, "jim7"));
        treeSet.add(new User(8, "jim4"));
        System.out.println(treeSet);
    }
map
 Map的key排序   TreeMap
  1. Map的key儲存的是自定義的類物件
    
   public static void main(String[] args) {

        TreeMap<User,Integer> treeMap = new TreeMap<>((user1,user2)->{
            return  user1.getName().compareTo(user2.getName());
        });
        treeMap.put(new User(1, "jim7"),1);
        treeMap.put(new User(1, "jim1"),1);
        treeMap.put(new User(8, "jim7"),1);
        treeMap.put(new User(8, "jim4"),1);
        System.out.println(treeMap);
    }  

泛型

泛型的好處
  • 將執行時期的ClassCastException,轉移到了編譯時期變成了編譯失敗。
  • 避免了型別強轉的麻煩
public class GenericDemo2 {
	public static void main(String[] args) {
        Collection<String> list = new ArrayList<String>();
        list.add("abc");
        list.add("itcast");
        // list.add(5);//當集合明確型別後,存放型別不一致就會編譯報錯
        // 集合已經明確具體存放的元素型別,那麼在使用迭代器的時候,迭代器也同樣會知道具體遍歷元素型別
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String str = it.next();
            //當使用Iterator<String>控制元素型別後,就不需要強轉了。獲取到的元素直接就是String型別
            System.out.println(str.length());
        }
	}
}

tips : 泛型是資料型別的一部分,我們將類名與泛型合併一起看做資料型別

泛型的定義與使用

泛型,用來靈活地將資料型別應用到不同的類、方法、介面當中。將資料型別作為引數進行傳遞。

含有泛型的類

定義格式:

修飾符 class 類名<代表泛型的變數> {  }

使用泛型: 即什麼時候確定泛型。

//舉例自定義泛型類

public class MyGenericClass<MVP> {
	//沒有MVP型別,在這裡代表 未知的一種資料型別 未來傳遞什麼就是什麼型別
	private MVP mvp;
     
    public void setMVP(MVP mvp) {
        this.mvp = mvp;
    }
     
    public MVP getMVP() {
        return mvp;
    }
}


//使用:

public class GenericClassDemo {
  	public static void main(String[] args) {		 
         // 建立一個泛型為String的類
         MyGenericClass<String> my = new MyGenericClass<String>();    	
         // 呼叫setMVP
         my.setMVP("大鬍子登登");
         // 呼叫getMVP
         String mvp = my.getMVP();
         System.out.println(mvp);
         //建立一個泛型為Integer的類
         MyGenericClass<Integer> my2 = new MyGenericClass<Integer>(); 
         my2.setMVP(123);   	  
         Integer mvp2 = my2.getMVP();
    }
}
含有泛型的方法

定義格式:

修飾符 <代表泛型的變數> 返回值型別 方法名(引數){  }
例:
public class MyGenericMethod {	  
    public <MVP> void show(MVP mvp) {
    	System.out.println(mvp.getClass());
    }
    
    public <MVP> MVP show2(MVP mvp) {	
    	return mvp;
    }
}

//使用格式:呼叫方法時,確定泛型的型別
public class GenericMethodDemo {
    public static void main(String[] args) {
        // 建立物件
        MyGenericMethod mm = new MyGenericMethod();
        // 演示看方法提示
        mm.show("aaa");
        mm.show(123);
        mm.show(12.45);
    }
}
含有泛型的介面

定義格式:

修飾符 interface介面名<代表泛型的變數> {  }
使用格式:

//1、定義類時確定泛型的型別
例如
public class MyImp1 implements MyGenericInterface<String> {
	@Override
    public void add(String e) {
        // 省略...
    }

	@Override
	public String getE() {
		return null;
	}
}
//此時,泛型E的值就是String型別。


//2、始終不確定泛型的型別,直到建立物件時,確定泛型的型別
 例如
public class MyImp2<E> implements MyGenericInterface<E> {
	@Override
	public void add(E e) {
       	 // 省略...
	}
	@Override
	public E getE() {
		return null;
	}
}
//確定泛型:
public class GenericInterface {
    public static void main(String[] args) {
        MyImp2<String>  my = new MyImp2<String>();  
        my.add("aa");
    }
}
泛型萬用字元

泛型的萬用字元:不知道使用什麼型別來接收的時候,此時可以使用?,?表示未知萬用字元。

public static void getElement(Collection<?> coll){}     
//這個類定義時用的問號 這樣子建立物件的時候只要不是同一個物件 可隨意定義資料型別
//遍歷時使用次數也比較多 
//?代表可以接收任意型別

public static void main(String[] args) {
    Collection<Intger> list1 = new ArrayList<Integer>();
    getElement(list1);
    Collection<String> list2 = new ArrayList<String>();
    getElement(list2);
}
萬用字元高階使用----受限泛型

之前設定泛型的時候,實際上是可以任意設定的,只要是類就可以設定。但是在JAVA的泛型中可以指定一個泛型的上限下限

泛型的上限

  • 格式型別名稱 <? extends 類 > 物件名稱
  • 意義只能接收該型別及其子類

泛型的下限

  • 格式型別名稱 <? super 類 > 物件名稱
  • 意義只能接收該型別及其父型別

比如:現已知Object類,String 類,Number類,Integer類,其中Number是Integer的父類

public static void main(String[] args) {
    Collection<Integer> list1 = new ArrayList<Integer>();
    Collection<String> list2 = new ArrayList<String>();
    Collection<Number> list3 = new ArrayList<Number>();
    Collection<Object> list4 = new ArrayList<Object>();
    
    getElement(list1);
    getElement(list2);//報錯
    getElement(list3);
    getElement(list4);//報錯
  
    getElement2(list1);//報錯
    getElement2(list2);//報錯
    getElement2(list3);
    getElement2(list4);
  
}
// 泛型的上限:此時的泛型?,必須是Number型別或者Number型別的子類
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此時的泛型?,必須是Number型別或者Number型別的父類
public static void getElement2(Collection<? super Number> coll){}

集合巢狀

城市級聯:
   一個省份有多個城市:
   可以根據省份獲得所有的城市資訊
  public static void main(String[] args) {
        //儲存資料  到集合
        List<String> city = new ArrayList<>(10);
        Collections.addAll(city, "鄭州市", "洛陽市", "鄭州市1", "鄭州市2", "鄭州市3");

        //可以根據省份獲得所有的城市資訊: ===> map: 根據key獲得value
        Map<String, List<String>> province = new HashMap<>(16);
        province.put("hn", city);

        city = new ArrayList<>(10);
        Collections.addAll(city, "石家莊市", "保定市", "保定1", "保定2", "保定3");
        province.put("he", city);
        System.out.println(province.get("he"));
    } 

Stream

List集合元素去重
    1.List 轉換  Set(利用set構造)
    2.Stream的distinct   
跟下面程式碼關係不大    
public static void main(String[] args) {

        //Stream: 支援並行化   操作集合元素
        //除了迭代器,我們能否在遍歷集合元素期間  對集合進行新增  刪除  修改等操作?
        //不可以。 ConcurrentModificationException

        //併發?
        //並行?
        //正在吃飯 有人打電話
        //1. 邊吃飯  邊打電話   並行
        //2. 吃了一口飯 與別人打電話  併發   cpu  上下文的切換時間  短---->專案中: 高併發(叢集  負載均衡)

        //在遍歷過程中  刪除符合條件的多個元素資料
        List<User> userList = new ArrayList<>(10);
        Collections.addAll(userList,
                new User(1, "jim1"),
                new User(10, "jim11"),
                new User(8, "jim3"),
                new User(7, "jim4"));

        System.out.println(userList);

//        userList.parallelStream().distinct()

        //刪除name中包含1的物件            //不支援  報錯
//        userList.forEach(user->{
//            if(user.getName().contains("1")){
//                userList.remove(user);
//            }
//        });                

        //1.獲得集合物件的Stream例項(集合的所有的元素儲存到Stream的物件中)
        Stream<User> userStream = userList.parallelStream();
        userStream.filter(new Predicate<User>() {
            @Override
            public boolean test(User user) {
                return !user.getName().contains("1");//過濾下來名字裡麵包含1
            }
        });
        userStream = userStream.filter(user -> !user.getName().contains("1"));
        //將過濾下來的元素 儲存到集合裡面去(收集起來)
        userList =  userStream.collect(Collectors.toList());
    
        //簡寫
        userList =  userList.parallelStream().filter(user -> !user.getName().contains("1")).collect(Collectors.toList());

//        System.out.println(userStream.count());
        System.out.println(userList);

    }

相關文章