[Java]集合

1.集合概述

集合框架:
在這裏插入圖片描述
集合框架是一個用來代表和操縱集合的統一架構。所有的集合框架都包含如下內容:

  • **接口:**是代表集合的抽象數據類型。例如 Collection、List、Set、Map 等。之所以定義多個接口,是爲了以不同的方式操作集合對象
  • **實現(類):**是集合接口的具體實現。從本質上講,它們是可重複使用的數據結構,例如:ArrayList、LinkedList、HashSet、HashMap。
  • **算法:**是實現集合接口的對象裏的方法執行的一些有用的計算,例如:搜索和排序。這些算法被稱爲多態,那是因爲相同的方法可以在相似的接口上有着不同的實現。

除了集合,該框架也定義了幾個 Map 接口和類。Map 裏存儲的是鍵/值對。儘管 Map 不是集合,但是它們完全整合在集合中。

collection 接口

是Collection層次結構中的根接口。Collection表示一組對象,稱爲collection的元素,一些collection允許有重複的元素,而一些則不允許,可以有序,或無序。此接口不提供任何直接實現,只提供更具體的子接口(如set和list實現)。此接口用來傳遞collection,並且在最大普遍性的地方操作這些collection。

2.List

public interface List< E > extends Collection< E >

有序的collection,也稱爲序列。此接口的用戶可以對列表中每個元素的插入位置進行精確的控制。用戶可以根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。

常用的有:ArrayList Vector LinkedList

public class ListDemo {
    private static void arrayList(){
        List<String> list = new ArrayList<>();
        list.add("xxx");
        list.add("yyy");
        list.add("zzz");
//        list.add(10);//未聲明list保存的類型時,可以保存多種類型的元素
        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
        if(list.contains("xxx")){
            System.out.println("contain xxx");
        }
        list.remove("yyy");
        String[] array = list.toArray(new String[]{});
        for(String s:array){
            System.out.println(s);
        }
    }
    public static void main(String[] args) {
        arrayList();
    }
}

2.1 ArrayList

實現原理:

  • 採用動態數組實現,默認構造方法創建了一個空數組
  • 第一次添加元素,擴展容量爲10,之後的擴充算法:原來數組大小+原來數組大小的一半
  • 不適合進行刪除或插入操作
  • 爲了防止數組動態擴充次數過多,建議創建ArrayList時,給定初始容量
  • 線程不安全,適合單線程訪問時使用,效率高。

2.2 Vector

實現原理:

  • 採用動態數組實現,默認構造方法創建了一個大小爲10的對象數組
  • vector的擴充算法:當增量爲0時,擴充爲原來大小的兩倍,當增量大於0時,擴充爲原來大小+增量。增量可以在初始化時給定
  • 不適合進行刪除或插入操作
  • 爲了防止數組動態擴充次數過多,建議創建Vector時,給定初始容量
  • 線程安全,適合在多線程訪問時使用,在單線程下使用效率低

2.3 LinkedList

實現原理:

  • 採用雙向鏈表結構實現
  • 適合插入,刪除操作,性能高

2.4 Vector和ArrayList和LinkedList的區別

  • ArrayList是最常用的List實現類,內部是通過數組實現的,它允許對元素進行快速隨機訪問。數組的缺點是每個元素之間不能有間隔,當數組大小不滿足時需要增加存儲能力,就要講已經有數組的數據複製到新的存儲空間中。當從ArrayList的中間位置插入或者刪除元素時,需要對數組進行復制、移動、代價比較高。因此,它適合隨機查找和遍歷,不適合插入和刪除。
  • Vector與ArrayList一樣,也是通過數組實現的,不同的是它支持線程的同步,即某一時刻只有一個線程能夠寫Vector,避免多線程同時寫而引起的不一致性,但實現同步需要很高的花費,因此,訪問它比訪問ArrayList慢。
  • LinkedList是用鏈表結構存儲數據的,很適合數據的動態插入和刪除,隨機訪問和遍歷速度比較慢。另外,他還提供了List接口中沒有定義的方法,專門用於操作表頭和表尾元素,可以當作堆棧、隊列和雙向隊列使用。
  • vector是線程(Thread)同步(Synchronized)的,所以它也是線程安全的,而Arraylist是線程異步(ASynchronized)的,是不安全的。如果不考慮到線程的安全因素,一般用Arraylist效率比較高。
  • 如果集合中的元素的數目大於目前集合數組的長度時,vector增長率爲目前數組長度的100%,而arraylist增長率爲目前數組長度的50%.如過在集合中使用數據量比較大的數據,用vector有一定的優勢。
  • 如果查找一個指定位置的數據,vector和arraylist使用的時間是相同的,都是0(1),這個時候使用vector和arraylist都可以。而如果移動一個指定位置的數據花費的時間爲0(n-i)n爲總長度,這個時候就應該考慮到使用Linkedlist,因爲它移動一個指定位置的數據所花費的時間爲0(1),而查詢一個指定位置的數據時花費的時間爲0(i)。
  • ArrayList 和Vector是採用數組方式存儲數據,此數組元素數大於實際存儲的數據以便增加和插入元素,都允許直接序號索引元素,但是插入數據要設計到數組元素移動 等內存操作,所以索引數據快插入數據慢,Vector由於使用了synchronized方法(線程安全)所以性能上比ArrayList要差,LinkedList使用雙向鏈表實現存儲,按序號索引數據需要進行向前或向後遍歷,但是插入數據時只需要記錄本項的前後項即可,所以插入數度較快!

實際開發中如何選擇list的具體實現

  • 是否考慮安全性問題
  • 是否頻繁插入,刪除操作
  • 是否是存儲後遍歷

3.Set

public interface Set< E > extends Collection< E >

一個不包含重複元素的collection,且最多包含一個null對象,無序。常用實現類:HashSet, TreeSet, LinkedHashSet

3.1 HashSet

實現原理:

  • 基於哈希表(HashMap)實現
  • 不允許重複,可以有一個null元素
  • 不保證順序恆久不變
  • 添加元素時把元素作爲HashMap的key來存儲,HashMap的value使用一個固定的object對象
  • 排除重複元素是通過equals來檢查對象是否相同
  • 判斷兩個對象是否相同,先判斷兩個對象的hashCode是否相同(如果兩個對象的hashCode相同,不一定是同一個對象,如果不同,那一定不是同一個對象),如果不同,則兩個對象不是同一個對象。如果相同,還要進行equals判斷,equals相同則是同一個對象,不同則不是同一個對象。
  • 自定義對象要認爲屬性值都相同時爲同一個對象,有這種需求時,我們要重寫對象所在的hashCode和equals方法。
public class SetDemo {
    private static void hashSet(){
        Set<String> set = new HashSet<>();
        set.add("xxx");
        set.add("yyy");
        set.add("xxx");//重複插入,只會保存一個
        System.out.println(set.size());
        String[] names = set.toArray(new String[]{});
        for(String s:names){
            System.out.println(s);
        }
        //插入的是對象
        Cat c1 = new Cat("xxx",4,1);
        Cat c2 = new Cat("yyy",5,3);
        Cat c3 = new Cat("zzz",1,4);
        Cat c4 = new Cat("xxx",4,1);
        Set<Cat> cats = new HashSet<>();
        cats.add(c1);
        cats.add(c2);
        cats.add(c3);
        cats.add(c4);
        System.out.println(cats.size());//當cat類沒有複寫hashCode和equals方法時,這裏的大小是4,因爲是不同的對象,如果有複寫,則是3
        for(Cat c:cats){
            System.out.println(c);
        }
        System.out.println("c1="+c1.hashCode()%16);
        System.out.println("c2="+c1.hashCode()%16);
        System.out.println("c3="+c1.hashCode()%16);
        System.out.println("c4="+c1.hashCode()%16);
    }
    public static void main(String[] args) {
       hashSet();
    }
}
public class Cat {
    private String name;
    private int age;
    private int id;

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

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

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }

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

    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;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

3.2 TreeSet

基於TreeMap的NavigableSet實現。使用元素的自然順序對元素進行排序,或者根據創建set時提供的Comparator進行排序,具體取決於使用的構造方法。

TreeSet 是有序的,基於TreeMap(二叉樹數據結構),對象需要比較大小,通過對象比較器來實現,對象比較器還可以取出重複元素。如果自定義的數據類沒有實現比較器Comparator這個接口,將無法添加到TreeSet中。

public class CatComparator implements Comparator<Cat> {
    @Override
    public int compare(Cat cat, Cat t1) {
        return cat.getAge()-t1.getAge();
    }
}
public class SetDemo {
    private static void treeSet(){
        TreeSet<Cat> tree = new TreeSet<>(new CatComparator());//需要實現比較器
        Cat c1 = new Cat("xxx",4,1);
        Cat c2 = new Cat("yyy",5,3);
        Cat c3 = new Cat("zzz",1,4);
        Cat c4 = new Cat("xxx",4,1);//相同的沒有插進去
        tree.add(c1);
        tree.add(c2);
        tree.add(c3);
        tree.add(c4);
        System.out.println(tree.size());
        for(Cat c:tree){
            System.out.println(c);
        }
    }
    public static void main(String[] args) {
        treeSet();
    }
}
/*
3
Cat{name='zzz', age=1, id=4}
Cat{name='xxx', age=4, id=1}
Cat{name='yyy', age=5, id=3}
*/

3.3 LinkedHashSet

具有可預知迭代順序的Set接口的哈希表和鏈接列表實現。此實現與HashSet的不同之處在於,其維護着一個運行於所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,即將元素插入到set中的順序(插入順序)進行迭代。插入順序不受set中重新插入的元素的影響。(如果在s.contains(e)返回true後立即調用s.add(e),則元素e會被重新插入到set s中。如果實現了hashCode和equals方法,則不會重複插入)。

這樣做的意義或者好處就是LinkedHashSet中的元素順序是可以保證的,也就是說遍歷序和插入序是一致的。

public class SetDemo {
    private static void linkedHashSet(){
        LinkedHashSet<Cat> tree = new LinkedHashSet<>();
        Cat c1 = new Cat("xxx",4,1);
        Cat c2 = new Cat("yyy",5,3);
        Cat c3 = new Cat("zzz",1,4);
        Cat c4 = new Cat("xxx",4,1);//相同的沒有插進去
        tree.add(c1);
        tree.add(c2);
        tree.add(c3);
        tree.add(c4);
        System.out.println(tree.size());
        for(Cat c:tree){
            System.out.println(c);
        }
    }
    public static void main(String[] args) {
        linkedHashSet();
    }
}
/*
3
Cat{name='xxx', age=4, id=1}
Cat{name='yyy', age=5, id=3}
Cat{name='zzz', age=1, id=4}
*/

4.集合的遍歷

  • foreach

  • Iterator

    對collection進行迭代的迭代器

    方法 介紹
    boolean hasNext() 如果仍有元素可以迭代,則返回true
    E next() 返回迭代的下一個元素
    void remove() 從迭代器指向的collection中移除迭代器返回的最後一個元素
  • ListIterator 列表迭代器,允許程序按任一方向遍歷列表,迭代期間修改列表,並獲得迭代器在列表中的當前位置。

    介紹
    void add(E e) 增加元素
    boolean hasPrevious() 判斷是否有前一個元素
    E previous() 取出前一個元素
    void set(E e) 修改元素的內容
    int previousIndex() 前一個索引位置
    int nextIndex() 下一個索引位置
  • Enumeration 實現Enumeration接口的對象,它生成一系列元素,一次生成一個。連續調用nextElement方法將返回一系列的連續元素。

    注:此接口的功能與Iterator接口的功能重複,建議使用Iterator

    方法 介紹
    boolean hasMoreElements() 判斷是否有下一個元素
    E nextElement() 取出當前元素
    public class IteratorDemo {
        //foreach
        private static void foreach(Collection<Cat> c){
            for(Cat cat:c){
                System.out.println(cat);
            }
            System.out.println("--------------------");
            c.forEach((Cat cat) -> {
                System.out.println(cat);
            });
            System.out.println("--------------------");
            c.forEach( cat -> {
                System.out.println(cat);
            });
            System.out.println("--------------------");
            c.forEach(System.out::println);
    
        }
        //iterator
        private static void iterator(Collection<Cat> c){
            Iterator<Cat> iter = c.iterator();
            while (iter.hasNext()){
                System.out.println(iter.next());
            }
        }
        private static void enumeration(){
            Vector<String> vs = new Vector<>();
            vs.add("xxx");
            vs.add("yyy");
            Enumeration<String> es = vs.elements();
            while (es.hasMoreElements()){
                System.out.println(es.nextElement());
            }
        }
    
        public static void main(String[] args) {
            List<Cat> list = new ArrayList<>();
            Cat c1 = new Cat("xxx",4,1);
            Cat c2 = new Cat("yyy",5,3);
            Cat c3 = new Cat("zzz",1,4);
            Cat c4 = new Cat("x7x",4,1);
            list.add(c1);
            list.add(c2);
            list.add(c3);
            list.add(c4);
            foreach(list);
    //        iterator(list);
    //        enumeration();
        }
    
    }
    

5.Map

public interface Map<k ,V>

將鍵映射到值的對象,一個映射不能包含重複的鍵,每個鍵最多隻能映射到一個值。

具體的實現類:HashMap, TreeMap, Hashtable, LinkedHashMap

方法 介紹
void clear() 清空Map集合中的內容
boolean containsKey(Object key) 判斷集合中是否存在指定的key
boolean containsValue(Object value) 判斷集合中是否存在指定的value
Set<Map,Entry<K,V>> entrySet() 將Map接口變爲Set集合
V get(Object key) 根據key找到其對應的value

5.1 HashMap

public class HashMap< K , V > extends AbstractMap< K, V > implements Map < K, V > ,Cloneable,Serializable

基於哈希表的Map接口的實現。此實現提供所有可選的映射操作,並允許使用null值和null鍵。(除了非同步和允許使用null之外,HashMap類與Hashtable大致相同。)此類不保證映射的順序,特別是它不保證該順序恆久不變。

public class MapDemo {
    private static void hashMap(){
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"xx");
        map.put(2,"yy");
        map.put(3,"zz");
        System.out.println("size = "+ map.size());
        System.out.println(map.get(1));
        //Map的遍歷1  遍歷entry
        Set<Entry<Integer,String>> entrySet =  map.entrySet();
        for(Entry e:entrySet){
            System.out.println(e.getKey()+"->"+e.getValue());
        }
        //Map的遍歷2  遍歷鍵
        Set<Integer> keys = map.keySet();
        for(Integer i:keys){
            String value = map.get(i);
            System.out.println(i+"->"+value);
        }
        //Map的遍歷3  遍歷值
        Collection<String> values = map.values();
        for(String s :values) {
            System.out.println(s);
        }
        //Map的遍歷4  foreacn
        map.forEach((key,value)-> System.out.println(key+"->"+value));
    }
    public static void main(String[] args) {
        hashMap();
    }
}

實現原理:

  • 基於哈希表(數組+鏈表+二叉樹(紅黑樹))二叉樹是1.8新增的
  • 加載因子0.75,默認數組大小爲16
  • 對象存儲在哈希表中,把key對象通過hash()方法計算hash值,用此hash值對數組長度取餘(默認16),來決定對key對象在數組中的存儲位置,當這個位置有多個對象時,以鏈表結構存儲,Jdk1.8後,當鏈表長度大於8時,鏈表將轉換爲紅黑樹結構存儲。目的是爲了取值時提高效率,取值更快。存儲的數據量越大,性能的表現越明顯。
  • 擴充原理:當數組的容量超過了75%,那麼表示該數組需要擴充。當前數組容量擴大一倍。擴充次數過多會影響性能,每次擴充時哈希表都會重新散列(重新計算每個對象的存儲位置)。
  • 線程不安全,適合單線程中使用。

5.2 Hashtable

public class Hashtable< K,V > extends Dictionary< K, V > implements Map< K,V >,Cloneable, Serializable

此類實現一個哈希表,該哈希表將鍵映射到相應的值。任何非null對象都可以用作鍵或值。爲了成功地在哈希表中存儲和獲取對象,用作鍵的對象必須實現hashCode方法和equals方法。

Hashtable與HashMap的區別:

  • Hashtable 從JDK1.0開始就有了,基於哈希表實現(數組+鏈表),默認數組大小爲11,加載因子0.75,擴充方式爲:原數組擴大一倍並+1。Hashtable是線程安全的,用於多線程。

5.3 LinkedHashMap

Map接口的哈希表和鏈接列表的實現,具有可預知的迭代順序。是HashMap的子類,可以保證順序恆久不變。此類使用一個雙重鏈表來維護元素添加的順序。

5.4 TreeMap

基於紅黑樹的NavigableMap實現。該映射根據其鍵的自然順序進行排序,或者根據創建映射時提供的Comparator進行排序,具體取決於使用的構造方法。

public class MapDemo {
    private static void treeMap(){
        Map<String,String> table = new TreeMap<>();
        table.put("one","lllll");
        table.put("two","xxxxx");
        table.put("three","bbbbb");
        table.forEach((key,value)-> System.out.println(key+"->"+value));

        Map<Dog,String> dogs = new TreeMap<>();
        dogs.put(new Dog("hhh",2,1),"lllll");
        dogs.put(new Dog("hx",5,2),"lll13");
        dogs.put(new Dog("hdfh",3,3),"lllll44");
        dogs.forEach((key,value)-> System.out.println(key+"->"+value));

    }


    public static void main(String[] args) {
        treeMap();
    }
}
public class Dog implements Comparable<Dog>{
    private String name;
    private int age;
    private int id;

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }

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

    //。。。getter setter。。。

    @Override
    public int compareTo(Dog dog) {
        return this.id-dog.id;
    }
}

5.5 JDK1.8添加的Map接口的新方法

public class MapNewMethodDemo {
    public static void main(String[] args) {
        Map<Integer,String> map = new HashMap<>();
        map.put(1,"jack");
        map.put(2,"tom");
        map.put(3,"lily");
        //取不到值時,使用默認值
        String value = map.getOrDefault(4,"null");
        System.out.println(value);
        //添加值,只會添加不存在key的值,如果已經存在key,則不會替換
        String val = map.putIfAbsent(3,"vince");
        System.out.println(val);
        //刪除 只有鍵和值都匹配時纔會刪除
        map.remove(3,"lily1");
        //代替
        map.replace(3,"vince");
        map.replace(3,"vince","vince1");//只有第一個參數的key,和第二個參數的value匹配,才能替換

        //計算,爲給定的key修改value
        map.compute(1,(k,v1)->v1+"1");
        map.computeIfAbsent(5,(k)->k+"xxx");//如果沒有這個k纔會添加
        //合併
        map.merge(1,"888",(oldv,newv)->oldv.concat(newv));
        //遍歷
        map.forEach((k,v)-> System.out.println(k+"->"+v));
    }
}

6.Collections工具類

Collections工具類提供了大量針對collection/map的操作,總體可分爲四類,都爲靜態方法。

6.1 排序操作

主要針對list接口

方法 介紹
reverse(List list) 反轉指定list集合中的元素順序
shuffle(List list) 對list中的元素進行隨機排序(洗牌)
sort(List list) 對list裏的元素根據自然升序排序
sort(List list,Comparator c) 自定義比較器排序
swap(List list,int i,int j) 將指定list集合中i處元素和j處元素進行交換
rotate(List list,int distance) 將所有元素向右移位指定長度,如果distance等於size那麼結果不變

6.2 查找和替換

主要針對Collection接口

方法 介紹
binarySerach(List list,Object key) 使用二分搜索,獲取指定對象在list中的索引,前提是集合已經排序
max(Collection coll) 返回最大元素
max(Collection coll, Comparator comp) 根據自定義比較器,返回最大元素
min(Collection coll) 返回最小元素
min(Collection coll, Comparator comp) 根據自定義比較器,返回最小元素
fill(List list,Object obj) 使用指定對象填充
frequency(Collection coll,Object o) 返回指定集合中指定對象出現的次數
replaceAll(List list,Object old,Object new) 替換

6.3 同步控制

Collections 工具類中提供了多個synchronizedXxx方法,該方法返回指定集合對象對應的同步對象,從而解決多線程併發訪問集合時線程的安全問題。HashSet、ArrayList、HashMap都是線程不安全的,如果需要考慮同步,則使用這些方法:synchronizedSet, synchronizedSortSet, synchronizedList, synchronizedMap, synchronizedSortMap。需要注意的是,在使用迭代方法遍歷集合時,需要手工同步返回的集合。

6.4 設置不可變集合

Collections 有三類方法可以返回一個不可變集合:

方法 介紹
emptyXxx() 返回一個空的不可變的集合對象
singletonXxx() 返回一個只包含指定對象的,不可變的集合對象
unmodifiableXxx() 返回指定集合對象的不可變視圖

6.5 其他

方法 介紹
disjoint(Collection< ? > c1, Collection< ? > c2 ) 如果指定collection中沒有相同的元素,則返回true
addAll(Collection< ? super T > c, T … a) 一種方便的方式,將所有指定元素添加到指定collection中
Comparator< T > reverseOrder (Comparator < T > cmp) 返回一個比較器,它強行反轉指定比較器的順序。如果指定比較器爲null,則此方法等同於reverseOreder()。(換句話說,它返回一個比較器,該比較器將強行反轉實現Comparable接口那些對象Collection上的自然順序)
public class CollectionsDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("xxx");
        list.add("yyy");
        list.add("zzz");
        //排序
//        Collections.reverse(list);
//        Collections.shuffle(list);
//        Collections.sort(list);
//        Collections.swap(list,0,2);
//        Collections.rotate(list,1);

        //查找和替換
//        System.out.println(Collections.binarySearch(list,"yyy"));
//        System.out.println(Collections.max(list));
//        System.out.println(Collections.min(list));
//        Collections.fill(list,"bin");
//        System.out.println(Collections.frequency(list,"xxx"));
//        Collections.replaceAll(list,"xxx","bin");

        //同步控制
        List<String> syncList = Collections.synchronizedList(new ArrayList<String>());

        //設置不可變集合,
//        List<String> slist = Collections.emptyList();
//        slist.add("bing");//會拋出異常,不可添加
        //這個不可變的空list可以用於方法返回值,在方法調用後得到的結果通過size來判斷是否有值,而不需要判斷是否爲空。
        /*比如:
        public static List<String> count(){
            List<String> list = null;
            if(....==null){
                return Collections.emptyList();
            }
        }
        List<String> li = count():
        if(li.size()==0){
            //....
        }
        */

        //反轉排序
        Collections.sort(list,Collections.reverseOrder());

        System.out.println("-------");
        list.forEach(System.out::println);
    }
}

7.Optional容器類(JDK1.8)

Opational容器類是一個可以爲null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法會返回該對象

方法 介紹
of 爲非null的值創建一個Optional
ofNullable 爲指定的值創建一個Optional,如果指定的值爲null,則返回一個空的Optional
isPresent 如果值存在則返回ture,否則false
get 如果Optional有值,則將其返回,否則拋出NoSuchElementException
ifPresent 如果Optional實例有值,則爲其調用consumer,否則不做處理
orElse 如果有值將其返回,否則返回他的指定值
orElseGet 與orElse類似,區別在於得到的默認值。orELse將傳入的字符串作爲默認值,orElseGet可以接受Supplier接口的實現用來生成默認值
orElseThrow 如果有值則將其返回,否則拋出supplier接口創建的異常
map 如果有值,則對其執行調用mapping函數得到返回值,如果返回值不爲null,則創建包含mapping返回值的Optional作爲map方法返回值,否則返回空optional
flatMap 如果有值,爲其執行mapping函數返回optional類型返回值,否則返回空optional。flatMap與map方法類似,區別在於flatMap中的mapper返回值必須是optional。調用結束時,flatMap不會對結果用optional封裝。
filter 如果有值並且滿足斷言條件,返回包含該值的optional,否則返回空optional
public class OpationalDemo {
    public static void main(String[] args) {
        //創建方式
        Optional<String> opt = Optional.of("bin");
//        Optional<String> opt1 = Optional.ofNullable("bin");
        Optional<String> opt2  = Optional.empty();
        System.out.println(opt.isPresent());
        System.out.println(opt.get());
        opt.ifPresent((value)-> System.out.println(value));
        System.out.println(opt2.orElse("沒有值"));
        System.out.println(opt2.orElseGet(()->"default"));
//        try {
//            opt2.orElseThrow(Exception::new);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
        Optional<String> opt3 = opt.map((value)->value.toUpperCase());
        System.out.println(opt3.orElse("no value"));

        Optional<String> opt4 = opt.flatMap((value)->Optional.of(value.toUpperCase()));
        System.out.println(opt4.orElse("no value"));

        Optional<String> opt5 = opt.filter((v)->v.length()>3);
        System.out.println(opt5.orElse("小於3"));
    }
}
/*
true
bin
bin
沒有值
default
BIN
BIN
小於3

Process finished with exit code 0

*/

8.Queue和Deque

隊列(Queue)是一種特殊的線性表,先進先出,只允許在表的前端(front,隊頭)進行刪除操作,在表的後端(rear,隊尾)進行插入操作。隊列中沒有元素時,稱爲空隊列。

LinkedList是Queue接口的實現類

方法 介紹
boolean add(E e) 向隊列插入元素,成功時返回true,如果沒有可用的空間,則拋出IllegalStateException
E element() 獲取但不移除隊頭元素
boolean offer(E e) 向隊列插入元素,成功時返回true,此方法優於add(E)
E peek() 獲取但不移除隊頭元素,若隊列爲空則返回null
E poll() 獲取並移除隊頭元素,若隊列爲空則返回null
E remove() 獲取並移除隊頭元素

Deque: 一個線性collection,支持在兩端插入和移除元素。

此接口既支持有容量限制的雙端隊列,也支持沒有固定大小限制的雙端隊列。接口定義在雙端隊列兩端訪問元素的方法,提供插入,移除和檢查元素的方法。

public class QueueDequeDemo {

    private static void queue(){
        Queue<String> queue = new LinkedList<>();
        queue.add("xxx");
        queue.add("yyy");
        queue.add("zzz");
        System.out.println(queue.size());
        System.out.println(queue.peek());
        System.out.println(queue.size());
        System.out.println(queue.poll());
        System.out.println(queue.size());
    }
    private static void deque(){
        Deque<String> deque = new LinkedList<>();
        deque.add("xxx");
        deque.add("yyy");
        deque.add("zzz");
        System.out.println(deque.size());
        System.out.println(deque.getFirst());
        System.out.println(deque.getLast());
    }
    public static void main(String[] args) {
        deque();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章