1. 程式人生 > 實用技巧 >java學習-集合、list、泛型、迭代器、併發異常

java學習-集合、list、泛型、迭代器、併發異常

一、集合體結構

  1.為什麼使用集合?

陣列容器是定長容器, 當定義出一個數組,必須指定長度;

集合容器,可以存放很多的資料, 但是集合是長度可變的容器(當集合容器中的資料儲存空間不夠, 系統會為集合進行自動擴容), 在實際開發中, 當並不知道資料有多少,集合就是最優秀的容器選擇

  2.集合體繫結構:

二、Collection集合

2.1 Collection的介紹和常用方法

  注意 : 所有集合中儲存的元素全部都是引用資料型別:

  如果需要儲存基本資料型別, 可以將基本型別進行自動裝箱, 變成引用儲存; 當使用集合中基本型別時, 再通過自動拆箱將資料獲取到;

  1.Collection集合 : 所有單列集合頂層父介面, 來自於java.util包,所有單列集合都需要實現Collection中的所有方法功能, Collection集合中具有List和Set集合中所有共有方法

  2.Collection 是介面,不能例項化物件, 因此需要一個Collection的實現類, 找到ArrayList, 運用介面多型性

Collection coll = new ArrayList();

  3.Collection中的常用方法:

    1)add(Object obj): 將引數obj新增到集合中, 末尾追加, 方法返回值型別boolean, 新增成功返回true,新增失敗返回false

    2)remove(Object obj) : 將引數obj元素從集合中刪除, 刪除成功, 返回true, 如果刪除失敗, 返回false

    3)clear() : 表示清空集合, 將集合中的所有元素全部刪除, 集合仍然存在

    4)isEmpty() : 驗證集合中是否有元素, 如果沒有元素,返回true; 如果有元素, 返回false

    5)size() : 表示獲取到集合中元素的個數(獲取集合的大小),返回值型別int型別              

    6)contains(Objectobj): 驗證集合中是否包含引數obj,如果包含返回true. 如果不包含返回false

程式碼

public class Demo01_Collection常用方法 {

    public static void main(String[] args) {
        Collection coll 
= new ArrayList(); // 1.add(Object obj): 將引數obj新增到集合中, 末尾追加, // 方法返回值型別boolean, 新增成功返回true,新增失敗返回false coll.add("a"); coll.add("b"); coll.add("c"); coll.add("hello"); System.out.println(coll);// [a, b, c, hello] System.out.println(coll.isEmpty());// false System.out.println(coll.contains("a"));// true System.out.println(coll.contains("c1"));// false // 2.remove(Object obj) : 將引數obj元素從集合中刪除, 刪除成功, 返回true, // 如果刪除失敗, 返回false System.out.println(coll.remove("c"));// true System.out.println(coll);// [a, b, hello] System.out.println(coll.size());// 3 // 3. clear() : 表示清空集合, 將集合中的所有元素全部刪除, 集合仍然存在 coll.clear(); System.out.println(coll);// [] // 4. isEmpty() : 驗證集合中是否有元素, 如果沒有元素,返回true; 如果有元素, 返回false boolean boo = coll.isEmpty(); System.out.println(boo);// true // 5. size():表示獲取到集合中元素的個數(獲取集合的大小),返回值型別int型別 System.out.println(coll.size());// 0 }

2.2 Collection集合的第一種遍歷方式

  1. 集合遍歷 : 表示將集合容器中的元素一個一個獲取到

  2. 使用Collection中的方法 :

    toArray() : 將一個集合中的所有元素放置到一個數組中(集合轉陣列), 返回值型別Object[], 通過遍歷陣列相當於遍歷集合

    注意 : 從Object型別陣列中獲取到的每一個元素,Object型別,想要轉換成集合中資料型別本身, 需要做多型的向下轉型

程式碼

public class Demo02_集合第一種遍歷 {
    public static void main(String[] args) {
         Collection coll = new ArrayList();
         // 12--->自動裝箱,Integer
         coll.add(12);
         coll.add(-78);
         coll.add(0);
         
         // 1. 將集合轉換成陣列
         Object[] objArr = coll.toArray();
         // 2. 遍歷陣列相當於遍歷集合
         for(int index = 0; index < objArr.length; index++) {
             // 3. 從Object型別陣列中獲取到的每一個元素,Object型別
             // 想要轉換成集合中資料型別本身, 需要做多型的向下轉型
             Integer i = (Integer)objArr[index];
             System.out.println(i+1);
         }
    }
}

2.3 Collection中所有帶All的方法

  1. addAll(Collection c) : 將引數集合c中的所有元素新增到方法呼叫集合中

  2. containsAll(Collection c) : 驗證方法呼叫集合中的元素是否完全包含了引數c集合中的元素,如果完全包含, 返回true; 如果不是完全包含, 返回false

  3. removeAll(Collection c) :將引數c集合中的所有元素從方法呼叫集合中刪除掉, boolean型別返回值結果(刪除兩個集合的交集)

  4. retainAll(Collection c) : 將方法呼叫集合與引數集合c中相同的元素保留下來, 同步到方法呼叫集合中(保留兩個集合的交集)

程式碼

public class Demo03_Collection中All方法 {

    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        
        Collection c1 = new ArrayList();
        c1.add("Hello");
        c1.add("a");
        
        // 1. addAll(Collection c) : 將引數集合c中的所有元素新增到方法呼叫集合中
        c.addAll(c1);
        System.out.println(c);//[a, b, Hello, a]
           
        System.out.println("--------------");
        
        // 2. containsAll(): containsAll(Collection c) : 驗證方法呼叫集合中的元素是否完全包含了引數c集合中的元素,如果完全包含, 返回true; 如果不是完全包含, 返回false
        boolean boo1 = c.containsAll(c1);
        System.out.println(boo1);// true
        
        Collection c2 = new ArrayList();
        c2.add("a1");
        c2.add("b");// [a1, b]
        
        System.out.println(c.containsAll(c2));// false
        System.out.println(c);// [a, b, Hello, a]
        System.out.println(c2);// [a1, b]
        
        // 3. removeAll(Collection c) :將引數c集合中的所有元素從方法呼叫集合中刪除掉, 
        // boolean型別返回值結果(刪除兩個集合的交集)
        c.removeAll(c2);
        
        System.out.println(c+"----");// [a, Hello, a]
        
        
        // 4.retainAll(Collection c) : 將方法呼叫集合與引數集合c中重疊(相同)的元素保留下來,同步到方法呼叫集合中(獲取兩個集合的交集)
        
        Collection cc = new ArrayList();
        cc.add("ui");
        cc.add("world");
        
        Collection cd = new ArrayList();
        cd.add("ui1");
        cd.add("world1");
        
        Collection ce = new ArrayList();
        ce.add("ui");
        ce.add("world____");
        
        /*cc.retainAll(cd);
        System.out.println(cc);// []
*/        
        cc.retainAll(ce);
        System.out.println(cc);//[ui]
    }
}

2.4 Collection集合第二種迭代器遍歷方式

  1.迭代 : 表示從一個到下一個的過程, 稱為迭代

  2.迭代器 : 專門用於將集合中的元素一個一個獲取到的物件

  3.迭代器物件的獲取和使用:

    Collection父介面中, 有一個方法 iterator() , 返回值型別Iterator(介面,表示迭代器介面), 因此iterator() 方法實際返回的是Iterator介面的一個實現類物件

    Iterator : 迭代器中的方法

      1)hasNext() : 判斷, 集合中是否還具有下一個元素, 如果有返回true; 如果沒有返回false

      2)next() : 獲取到集合中的下一個元素, 返回值型別Object

      3)remove() : 使用迭代器物件將目前正在迭代的元素從集合中刪除

程式碼

public class Demo04_迭代器遍歷集合 {

    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("Hello");
        
        // 目前對於集合中有集合元素,未知,使用迴圈一次將元素從集合中獲取到
        // 1. 獲取一個集合的迭代器物件
        Iterator it = c.iterator();
        // 2. 使用迭代器中的nextInt()方法功能判斷集合中是否具有下一個元素
        while(it.hasNext()) {
            // 3. 集合中有下一個元素,next獲取到這個元素
            Object obj = it.next();
            String s = (String)obj;
            System.out.println(s);
        }
        
        // 4. 當集合已經遍歷完畢, 但是還要通過next獲取集合中的元素
        // 丟擲異常 : NoSuchElementException
        System.out.println(it.next());
    }
}

三、List集合

3.1List集合的介紹和特有方法

  1.List集合是Collection介面的一個子介面,來自於java.util包

  2.List集合的特點:

    1)List集合中元素儲存有序 : 存入集合的順序與取出的順序保持一致

    2)List集合中的元素都具有索引位置, 索引範圍0---集合長度-1 (size()-1)

    3)List集合中儲存的元素可以重複

  3.List中的特有方法: 都與索引操作有關

    1)add(int index, Object obj) : 將引數obj新增到集合指定索引index位置處

    2)remove(int index) : 將集合中指定index索引位置的元素刪除, 返回值型別Object型別, 將刪除的元素值進行返回

    3)set(int index, Object obj) : 將集合中指定index索引位置上的元素,使用obj進行替換, 返回值型別Object, 將被替換掉的原值進行返回

    4)get(int index) : 將集合中指定index索引位置上的元素獲取到, 返回值型別Object

程式碼

public class Demo01_List特有方法 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("a");
        list.add("b");
        
        // 1. add(int index, Object obj) : 將引數obj新增到集合指定索引index位置處
        list.add(0, "第一");
        System.out.println(list);//[第一, a, b]
        
        // 2. remove(int index) : 將集合中指定index索引位置的元素刪除, 返回值型別Object型別, 將刪除的元素值進行返回
        Object obj = list.remove(1);
        System.out.println(obj);// a
        System.out.println(list);// [第一, b]
        
        // 3.set(int index, Object obj) : 將集合中指定index索引位置上的元素,使用obj進行替換, 返回值型別Object, 將被替換掉的原值進行返回
        Object obj1 = list.set(0, "替換");
        System.out.println(obj1);// 第一
        System.out.println(list);// [替換, b]
        
        // 4.get(int index) : 將集合中指定index索引位置上的元素獲取到, 返回值型別Object
        Object obj2 = list.get(0);
        System.out.println(obj2);// 替換
        
        System.out.println(list.get(1));// b
        
        // 出現異常 : IndexOutOfBoundsException: Index: 2, Size: 2
        // System.out.println(list.get(2));
    }
}

3.2List集合第三種遍歷方式

  本種遍歷方式是List集合特有的方法

  1.get(int index) : 將集合中指定index索引位置上的元素獲取到

  2.如果能獲取到一個集合的所有索引,那麼可以通過get方法獲取到集合中的每一個元素(與陣列的遍歷很相似)

  集合的索引範圍 : 0---集合長度-1 (size()-1)

程式碼

public class Demo01_List第三種遍歷 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("89");
        
        // 設計迴圈,獲取集合中的每一個索引位置
        for(int index = 0; index < list.size(); index++) {
            // 使用get(index)方法即可
            System.out.println(list.get(index));
        }
    }
}

3.3併發修改異常

  1. ConcurrentModificationException 併發修改異常
  2. 異常發生原因 :

當使用【迭代器物件】迭代集合同時, 使用【集合物件】向集合中新增或者刪除元素, 導致迭代不能保證正確性, 於是報出併發修改異常

  3.異常解決方案:

    1)迭代器物件迭代, 也使用迭代器物件修改

    2)使用List集合特有遍歷方式 : 索引

  4.實際解決方式:

    1)迭代器物件迭代, 也使用迭代器物件修改

  在List介面中,有特殊方法:

      a :listIterator() : 返回值型別ListIterator(介面), 也是一個迭代器型別,但是在原有的迭代器功能基礎上,支援一邊迭代集合,一邊修改集合中的元素,而避免發生併發修改異常.切記一定要使用迭代器物件修改集合元素

      b : ListIterator介面中的方法 :

        add(Object obj) : 使用迭代器物件向集合中新增元素obj

    2)使用List集合特有遍歷方式 : 索引

  因為for迴圈只是語法結構,不是任何型別 , 因此for迴圈本身不會發生異常; 並且每次for迴圈的條件都會實時獲取到集合的長度, 也會適當的保證迭代的準確性

需求 : 定義出一個集合,集合中有三個元素 “hello”“world”“ok”, 遍歷集合,當元素值匹配”hello”,向集合中新增元素”add”

程式碼

public class Demo03_併發修改異常 {
    /*需求 : 定義出一個集合,集合中有三個元素 “hello” “world” “ok” , 
    遍歷集合,當元素值匹配”hello”時,向集合中新增元素”add”*/
    public static void main(String[] args) {
         List list = new ArrayList();
         list.add("hello");
         list.add("world");
         list.add("ok");
         
         /* 發生併發修改異常
          * Iterator it = list.iterator();
         while(it.hasNext()) {
             Object obj = it.next();
             String s = (String)obj;
             if("hello".equals(s)) {
                 list.add("add");
             }
         }
         
         System.out.println(list);*/
         
         // 併發修改異常第一種避免方案
         // 1. 獲取到List集合特有的迭代器物件ListIterator
         /*ListIterator it = list.listIterator();
         while(it.hasNext()) {
             Object obj = it.next();
             String s = (String)obj;
             if("hello".equals(s)) {
                 // 2, 讓迭代器物件給集合新增元素
                 // it.add("add");
                 it.remove();
             }
         }
         System.out.println(list);*/  
         
         // 併發修改異常第二種避免方案
         for(int index = 0; index < list.size(); index++) {
            String s = (String)list.get(index);
            if("hello".equals(s)) {
                  // list.add(0,"add");// [add,add,hello,world,ok] 造成死迴圈
                  list.add("add");
               }
         }
         System.out.println(list);// [hello, world, ok, add]
    }
}

3.4List集合的實現類

  1. List介面, 需要實現類 : 根據底層實現不同,有不同的實現類
  2. List的實現類中,使用比較多的有2個

    1)ArrayList : 陣列實現(ArrayList底層陣列結構), 順序儲存

    2)LinkedList : 節點實現(可以利用記憶體中零散空間), 鏈式儲存

  3.4.1ArrayList實現類

  1. ArrayList 實現類 : 陣列實現(ArrayList底層陣列結構), 順序儲存

  ArrayList查詢快, 增加刪除元素,相對比較慢

  

3.4.2 LinkedList實現類

  1. LinkedList : 節點實現(可以利用記憶體中零散空間), 鏈式儲存

  LinkedList查詢慢, 增加刪除元素,相對比較快

  節點實現 : LinkedList中的元素節點儲存, 每一個節點分為兩個部分, 其中一個部分用於儲存集合中的元素, 另外一個部分儲存是下一個元素的地址值

  2.LinkedList型別中儲存起始點記憶體地址(第一個元素); 還會儲存最後一個節點記憶體地址(最後一個元素)

  因此LinkedList中對於第一個元素位置和最後一個元素的位置有特殊方法

    1)addFirst()

    2)addLast()

    3)removeFirst()

    4)removeLast()

    5)getFirst()

    6)getLast()

上述對於頭尾操作的方法,效能比較高

程式碼

public class Demo04_LinkedList {
    public static void main(String[] args) {
         LinkedList list = new LinkedList();
         list.addFirst("a");
         list.addFirst("1");
         list.addLast("end");
         list.addLast("end1");
         
         System.out.println(list.getFirst());// 1
         System.out.println(list.getLast());// end1
         
         list.removeFirst();// 1
         list.removeLast();//  end1
         
         System.out.println(list);// [a, end]
    }
}

四、泛型

4.1泛型的概述和使用(掌握)

  1. 泛型 : 表示廣泛的型別(泛型是引用資料型別), 定義一個型別時, 對於這個型別中的一些方法引數或者返回值型別無法確定, 於是使用一個符號表示,這個符號稱為泛型
  2. 泛型的使用:

  在型別聲明後,使用<>,在菱形尖括號中,寫入大寫字母, 這些大寫字母就表示泛型, 當創建出這個型別物件的時候, 需要確定泛型的具體型別

確定泛型E具體型別時候:

  a : 類上定義的泛型,可以在整個類中當做一個已知型別進行使用

  b : 舉例 : ArrayList<E> , 這個E型別在ArrayList類中可以直接使用

    public boolean add(E e){} // E與ArrayList上面的廣泛型別一致

    ArrayList<String> list = new ArrayList<>();

    list容器泛型確定為String型別, add方法引數型別就確定為String,呼叫時add(String s)

  1.泛型的好處:

    1)提高程式碼的安全性, 將在執行環節會發生的問題提前到程式碼編譯環節

    2)提交程式碼的簡潔性, 在集合中使用泛型,可以避免掉集合資料獲取的向下轉型操作

    3)使用集合一定要使用泛型

  2.泛型寫作的注意事項:

    1)一致性 : 前後的泛型型別必須一致

    2)泛型推斷 : 從JDK1.7版本開始,後面的泛型可以不寫, 只寫<>, 預設後面的泛型型別與前面的型別保持一致

程式碼

public class Demo01_泛型的使用和好處 {
    public static void main(String[] args) {
        // 當創建出一個ArrayList集合容器時, 需要確定這個容器中儲存的資料型別
        // 集合型別通過泛型的方式進行確定
        // list集合中只能儲存Integer型別資料
       ArrayList<Integer> list = new  ArrayList<Integer>();
       list.add(12);
       list.add(13);
       list.add(14);
       list.add(15);
       
       for(int index = 0; index < list.size(); index++) {
           Integer i = list.get(index);
           System.out.println(i + 1);
       }
       
       ArrayList<String> list2 = new ArrayList<>();
       list2.add("abc");
       
       /*ArrayList list1 = new ArrayList();
       list1.add("a");
       list1.add(12);
       list1.add(3.14);
       
       for(int index = 0; index < list1.size(); index++) {
           Object obj = list1.get(index);
           String s = (String)obj;
           System.out.println(s); 
       }*/
    }
}