Java 集合

1 java集合的接口框架
集合的接口框架


集合1.png

Java集合分為Collections和Map兩大種。

2 Collection集合
定義了Collection集合分支的基礎方法,有查詢方法,修改集合方法,批量操作方法和比較與hash方法,這些都是集合的基礎方法。

package java.util;
 
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
 
public interface Collection<E> extends Iterable<E> {
    // Query Operations
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
 
    // Modification Operations
    boolean add(E e);
    boolean remove(Object o);
 
    // Bulk Operations
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
    boolean retainAll(Collection<?> c);
    void clear();

    // Comparison and hashing
    boolean equals(Object o);
    int hashCode();
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
}

Collection分為這幾類
1.List: 有序集合,值允許有重復
2.Set:無需集合,值不允許有重復
3.Queue:保持先進先出順序

2.1 List集合: ArrayList&LinkedList
ArrayList的基礎數據結構是數組,數組因為可以通過下標訪問成為一個隨機訪問第n個數效率很高的數據結構,隨機訪問查詢的時間復雜度是O(1),查詢某個定值的時間復雜度是O(n),刪除/增加新的元素到某個位置時,需要一個一個的移動數組中的元素直至適合的位置,所以時間復雜度是O(n)

LinkedList的基礎數據結構是鏈表,在java中鏈表的每一個節點具有指向前結點的prev引用和指向后結點next引用,即雙向鏈表。正是因為這樣的設計,在鏈表中插入元素時,只需要改變插入位置前后結點的結點指向和添加新元素的結點指向即可,時間復雜度是O(1),在訪問元素的時候,無論是隨機方位第幾位的元素還是查詢某個定值時,鏈表的時間復雜度均為O(n)

所以,根據實際場景,如果查詢操作比較多的話,建議采用ArrayList等數組實現的List,效率會高。

在java中,LinkedList也提供根據index獲得元素的方法

/**
 * Returns the element at the specified position in this list.
 *
 * @param index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

每次查找一個元素都要從列表的頭部重新開始搜索,LinkedList對象不做任何緩存位置信息的操作,所以循環遍歷獲取LinkedList對象的數據值,效率不高。

for (int i = 0; i < linkedList.size(); i++){
    do something with linkedList.get(i);
}

2.2 Set集合: HashSet&TreeSet
HashSet:不會對放入集中的數據進行排序,基于Hash存儲與查找數據。在java中,散列表用鏈表數組實現,每個列表被稱為桶,想要查找表中的對象,需要先計算他的hashCode,然后與桶的總數取余,所得到的結果就是保存這個元素的桶的索引。一般裝填因子是0.75,保持一個好的裝填因子與桶的數目,可以減少hash沖突,使每次查找盡量一次定位找到,采用has方式查找元素的時間復雜度是O(1)

TreeSet:對放入集中的數據進行排序,他是一個有序的集合,可以以任意順序將元素插入到集合中,在對集合進行遍歷時,每個值將自動地按照排序后的順序呈現,他采用的數據結構是紅黑樹。每次將一個元素添加到樹中,都被放置在正確的排序位置上,因此,迭代器總是以排好序的順序訪問每個元素。

將一個元素添加到樹中要比添加到散列表中慢,但是與將元素添加到數組或者鏈表的正確位置上還是快很多的。如果樹中包含n個元素,查找新元素的正確位置平均需要log2 n次比較。

如果所要收集的數據,不需要排序的話,那么并不需要付出排序的開銷即可以考慮HashSet

TreeSet如何知道希望元素怎么排列呢?

2.3 對象的比較: Comparable&Comparator
Comparable:是排序接口,若一個類實現了Comparatable接口,就意味著“該類支持排序”,既然實現Comparable接口的類支持排序,假設現在存在“實現Comparable接口的對象的List數組”,則該List列表或者數組可以通過Collection.sort(或Arrays.sort)進行排序。實現Comparable接口的類的對象可以用作有序映射(e.g.TreeMap)中的“鍵值”或“有序集合(e.g.TreeSet)中的元素”,而不需要指定比較器。

package java.lang;
import java.util.*;
public interface Comparable<T> {    
    public int compareTo(T o);
}

Comparator:比較器接口,如果需要控制某個類的次序,而該類本身不支持排序(沒有實現Comparable接口),那么我們可以建立一個“該類的比較器”來進行排序,這個“比較器”只需要實現Comparator接口即可,我們可以通過“實現Comparator類來建立一個比較器”,然后通過該比較器對類進行排序。

package java.util;
public interface Comparator<T> {    
    int compare(T o1, T o2);    
    boolean equals(Object obj);
}

Comparable相當于“內部比較器”,而Comparator相當于“外部比較器”。
Comparable&Comparator使用:

public class Item implements Comparable<Item> {
    private String description;
    private int partNumber;
 
    public Item(String description, int partNumber) {
        this.description = description;
        this.partNumber = partNumber;
    }
 
    public String getDescription() {
        return description;
    }
 
    public void setDescription(String description) {
        this.description = description;
    }
 
    public int getPartNumber() {
        return partNumber;
    }
 
    public void setPartNumber(int partNumber) {
        this.partNumber = partNumber;
    }
 
    @Override
    public String toString() {
        return "Item{" +
                "description='" + description + '\'' +
                ", partNumber=" + partNumber +
                '}';
    }
 
    @Override
    public boolean equals(Object otherObject) {
        if (this == otherObject){
            return true;
        }
        if (otherObject == null){
            return false;
        }
        if (getClass() != otherObject.getClass()){
            return false;
        }
        Item other = (Item)otherObject;
        return Objects.equals(description, other.description) && partNumber == other.partNumber;
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(description, partNumber);
    }
 
    @Override
    public int compareTo(Item other) {
        return Integer.compare(partNumber, other.partNumber);
    }
}
  
public class ComparatorTest {
@Test
public void treeSetTest(){
    SortedSet<Item> parts = new TreeSet<Item>();
    parts.add(new Item("Toaster", 1234));
    parts.add(new Item("Widget", 4562));
    parts.add(new Item("Modem", 9912));
    SortedSet<Item> sortByDescription = new TreeSet<Item>(new Comparator<Item>() {
        public int compare(Item a, Item b) {
            String descA = a.getDescription();
            String descB = b.getDescription();
            return descA.compareTo(descB);
        }
    });
    sortByDescription.addAll(parts);
    System.out.println(sortByDescription);
    }
}

2.4 Queue: PriorityQueue
優先級隊列,元素可以按照任意的順序插入,但總是按照排序的順序進行檢索,內部實現的數據結構是堆。堆是一個可以自我調整的二叉樹,對樹執行添加和刪除的時候,可以讓最小的元素移動到根,而不用花費時間對元素進行排序。使用的典型實例是任務調度場景。

3 Map集合
鍵值對,鍵必須是唯一的,不能對同一個鍵存放兩個值,Map的基礎方法

public interface Map<K,V> {
    // Query Operations
    int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    V get(Object key);
 
    // Modification Operations
    V put(K key, V value);
    V remove(Object key);
 
    // Bulk Operations
    void putAll(Map<? extends K, ? extends V> m);
    void clear();
 
 
    // Views
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();
 
    interface Entry<K,V> {
        K getKey();
        V getValue();
        V setValue(V value);
        boolean equals(Object o);
        int hashCode();
 
        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
        }
 
        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
        }
 
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
        }
 
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
        }
    }
 
    // Comparison and hashing
    boolean equals(Object o);
    int hashCode();
 
    // Defaultable methods
    default V getOrDefault(Object key, V defaultValue) {
        V v;
        return (((v = get(key)) != null) || containsKey(key))
            ? v
            : defaultValue;
    }
 
    default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }
 
    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Objects.requireNonNull(function);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
 
            // ise thrown from function is not a cme.
            v = function.apply(k, v);
 
            try {
                entry.setValue(v);
            } catch(IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
        }
    }
 
    
    default V putIfAbsent(K key, V value) {
        V v = get(key);
        if (v == null) {
            v = put(key, value);
        }
 
        return v;
    }
 
    default boolean remove(Object key, Object value) {
        Object curValue = get(key);
        if (!Objects.equals(curValue, value) ||
            (curValue == null && !containsKey(key))) {
            return false;
        }
        remove(key);
        return true;
    }
 
    default boolean replace(K key, V oldValue, V newValue) {
        Object curValue = get(key);
        if (!Objects.equals(curValue, oldValue) ||
            (curValue == null && !containsKey(key))) {
            return false;
        }
        put(key, newValue);
        return true;
    }
 
    default V replace(K key, V value) {
        V curValue;
        if (((curValue = get(key)) != null) || containsKey(key)) {
            curValue = put(key, value);
        }
        return curValue;
    }
 
    default V computeIfAbsent(K key,
            Function<? super K, ? extends V> mappingFunction) {
        Objects.requireNonNull(mappingFunction);
        V v;
        if ((v = get(key)) == null) {
            V newValue;
            if ((newValue = mappingFunction.apply(key)) != null) {
                put(key, newValue);
                return newValue;
            }
        }
 
        return v;
    }
 
    default V computeIfPresent(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        V oldValue;
        if ((oldValue = get(key)) != null) {
            V newValue = remappingFunction.apply(key, oldValue);
            if (newValue != null) {
                put(key, newValue);
                return newValue;
            } else {
                remove(key);
                return null;
            }
        } else {
            return null;
        }
    }
 
    default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        V oldValue = get(key);
 
        V newValue = remappingFunction.apply(key, oldValue);
        if (newValue == null) {
            // delete mapping
            if (oldValue != null || containsKey(key)) {
                // something to remove
                remove(key);
                return null;
            } else {
                // nothing to do. Leave things as they were.
                return null;
            }
        } else {
            // add or replace old mapping
            put(key, newValue);
            return newValue;
        }
    }
 
    default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        V oldValue = get(key);
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        if(newValue == null) {
            remove(key);
        } else {
            put(key, newValue);
        }
        return newValue;
    }
}

a.Map的三個視圖方法

Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();

分別是獲得鍵集、值集合鍵值對集

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容

  • Collection & Map Collection 子類有 List 和 Set List --> Array...
    任教主來也閱讀 3,182評論 1 9
  • 以下資料是在學習中總結出來的,希望對你有所幫助。如果需要請轉載,謝謝。 1. StringBuffer 線程安全,...
    尚學先生閱讀 734評論 0 1
  • 本文取自工匠若水的qq群里的Java基礎題目,把里面有關Java集合放在一起。全文github地址 35.Arra...
    蟬翅的空響閱讀 252評論 0 0
  • 最近新任縣長在全縣安全生產工作會議上講的一句話發人深省。他說:今天的隱患就是明天的事故,所以要向前一步解決問...
    松峰說教劉樹森閱讀 667評論 0 1
  • 最近我發現我每做一件事情都會深入到自己內心,會問問自己內心真實的想法,通過內心的一個呈現我在探索我自己,我這個人到...
    十碗汁閱讀 303評論 0 0