JAVA collection learning notes

Posted by Lodius2000 on Sat, 11 Dec 2021 07:16:44 +0100

Advantages and disadvantages of arrays and collections

Advantages of arraysDisadvantages of arrays
Simple definition and quick accessImmutable length after initialization
After definition, the type is single
The methods provided are limited, inconvenient to insert, delete and other operations, and the efficiency is not high
There is no method to get the actual elements of the array
Continuous storage space is required. For more elements, a large continuous space needs to be opened up
Advantages of set
Dynamically save multiple objects with variable length
Multiple type elements can be saved
Provide methods for operating object elements, such as add, remove, set, get, etc

Collection

Only common collections are listed here

Collection features

  • collection implementation subclasses store elements that are object objects and will be automatically boxed

  • If you do not use generics, the object object is returned by default

    List list = new ArrayList();//Since the interface cannot be instantiated, the ArrayList class is used to implement the interface
    list.add(1);//Automatic packing, storing integer object list add(new (Integer(1)))
    list.add("tom");
    list.add(true);
    

Collection common methods

  • Add: add a single element

  • remove: deletes a single element

  • contains: find whether a single element exists

  • size: get the number of elements

  • isEmpty: judge whether it is empty

  • Clear: clear

  • addAll: add multiple elements (first store the elements in the collection, and then use this method to add the collection)

  • containsAll: find whether multiple elements exist (also through collection operation)

  • removeAll: delete multiple elements (through collection operations)

Collection iterative traversal

Iterator object iterator

Iterator object iterator in iteratable, all collections implement this method; Two main methods are used:

  • hasNext: judge whether the next element exists
  • Next: take out the next element

Before using next, you must call hasNext to determine whether the next element exists. If it is not called and the next piece of data is empty, an exception will be thrown.

Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()){
    //Return the element object,
    Object obj = iterator.next();
    System.out.println(obj);
}

Enhanced for loop

for (Object obj:list){
    System.out.println(obj);
}
  • Is the underlying Iterator

  • Can be understood as a simplified version of the iterator

Normal for loop

for (int i=0;i<list.size();i++){
    Object obj = list.get(i);
    System.out.println(obj);
}

List

List is also an interface. Here, the ArrayList class is used to implement the interface

characteristic

  • List collection elements are ordered and repeatable

    List<Object> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.add(1);
    System.out.println(list);
    
    Output:[1, 2, 3, 4, 1]
    
  • Each element of List has a corresponding index, which supports index operation. The index starts from 0

    List<Object> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.add(1);
    System.out.println(list.get(3));
    
    Output: 4
    

List common methods

  • Add (object): add an element

  • add (int index, Object obj): insert the element obj where the index is the index

    List<Object> list = new ArrayList<>();
    list.add(0);
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(1,100);
    System.out.println(list);
    
    Output:[0, 100, 1, 2, 3]
    
  • addAll (Collection eles): add multiple elements (first store the elements in the collection, and then use this method to add the collection)

  • addAll (int index, Collection eles): inserts elements in the Collection eles at the index position

  • Get (int index): get the element at the index position

  • indexOf (object obj): returns the position where obj first appears in the collection

  • lastIndexOf (object obj): returns the location of the last occurrence of obj in the collection

  • remove (int index): removes the element at the index position and returns it

  • set (int index, object obj): replace the Suntech element at the index position with obj, and the index must exist

  • subList (int fromIndex, int toIndex): returns a substring, closed on the left and open on the right [fromIndex,toIndex)

ArrayList

characteristic

  • Multiple null s can be placed

    List<Object> list = new ArrayList<>();
    list.add(null);
    list.add(null);
    list.add(2);
    System.out.println(list);
    
    Output:[null, null, 2]
    
  • The bottom layer is implemented by array

  • ArrayList is basically equivalent to Vector, but ArrayList is thread unsafe and is not decorated with synchronized (high execution efficiency because thread safety is not considered),

  • ArrayList is not recommended for multilinear applications

ArrayList capacity expansion mechanism (key)

  • An array of Object type is used to store objects in ArrayList

    transient Object[] elementData; //The transient modifier indicates that the property will not be serialized
    
  • When creating an ArrayList object, if a parameterless constructor is used, initialize the array size to 0, add elements for the first time, expand the array capacity to 10, and each subsequent expansion is 1.5 times the previous one

    List list = new ArrayList();//Initialization size is 0
    
  • If the parameterized constructor of the specified size is used directly, the initialization array size will be the specified size, and each subsequent expansion will be 1.5 times the previous one

    List list = new ArrayList(5);//The initialization size is the specified 5
    

Nonparametric construction source code

  • Initialize the array and create the elementData array

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//The array is empty, that is, the size is 0
    
  • Execute add

    //Type packing operation. Different types correspond to different packing classes
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    
  • First determine whether the array capacity is sufficient

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
  • If the capacity is insufficient, call grow to expand the capacity

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length; //The first oldCapacity=0
        int newCapacity = oldCapacity + (oldCapacity >> 1);  //1.5x capacity expansion
        if (newCapacity - minCapacity < 0) //If the first expansion newCapacity=0
            newCapacity = minCapacity;  //The expansion result is minCapacity=10
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity); //When the array is expanded to the size of newCapacity, copyOf will retain the original data
    }
    

Vector

characteristic

  • Multiple null s can be placed

  • The bottom layer is also an array

  • Vector is thread synchronization, that is, thread safety (low efficiency). The vector operation method has the synchronized keyword

    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
    

Capacity expansion mechanism

  • If the parameterless constructor is used, the initialization array size is 10, and the subsequent capacity expansion is twice that of the previous one. The incremental size can be changed in the constructor
  • If you directly use a parameterized constructor of the specified size, the initialization array size is the specified size, and each subsequent expansion is twice the previous size. You can change the incremental size in the constructor

LinkedList

characteristic

  • The bottom layer implements two-way linked list and two end queue
  • Thread is unsafe and thread synchronization is not implemented
  • Adding and deleting does not require array expansion and is efficient

LinkedList underlying operation mechanism

  • The underlying LinkedList maintains a two-way linked list

  • Maintain two nodes, first and last, pointing to the first node and the tail node respectively

  • Each Node (Node object) maintains three attributes: prev, next and item

  • prev goes straight to the previous node, and next points to the next node. Finally, the two-way linked list is realized

LinkedList method

  • add (object): tail interpolation, inserting objects

  • add (int index, object obj): insert the obj element where the index is the subscript

    List list = new LinkedList();
    list.add(0);
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(3,10);
    System.out.println(list);
    
    Output:[0, 1, 2, 10, 3]
    
  • set (int index, object obj): change the location element with index as the subscript to the obj element

    List list = new LinkedList();
    list.add(0);
    list.add(1);
    list.add(2);
    list.add(3);
    list.set(2,"obj");
    System.out.println(list);
    
    Output:[0, 1, obj, 3]
    
  • remove (int index): delete the element with index as the subscript

  • remove (object obj): delete the element whose object is obj. If there are multiple obj, delete the first one

  • Get (int index): get the element with index as the subscript

  • . . .

ArrayList and LinkedList comparison

Bottom structureAddition and deletion efficiencyModification efficiency
ArrayListarrayArray expansion, lowhigher
LinkedListBidirectional linked listOperation node pointer, highLower

How to choose

  • Select ArrayList instead of multiple queries

  • To add or delete more, select LinkedList

  • Generally speaking, 80% - 90% are queries, so most of them choose ArrayList

Set

HashSet

characteristic

  • Out of order (inconsistent order of addition and extraction), no index

  • For the same set of data, no matter how the addition order changes, the output order is fixed (sorted internally according to the hash value)

  • Duplicate elements are not allowed, so it can contain at most one null

            Set set = new HashSet();
            set.add(1);
            set.add(3);
            set.add("jack");
            set.add("jack"); //The same element cannot be added. There is jack in the constant pool
            set.add(new Dog("tom"));
            set.add(4);
            set.add(new Dog("tom")); // Different objects have different addresses, so they can be added
            set.add(null);
            set.add(2);
            set.add(new String("lucy"));
            set.add(new String("lucy")); //Cannot add
            System.out.println(set);  
    
           Output:[null, 1, 2, 3, Dog{name='tom'}, 4, Dog{name='tom'}, lucy, jack]
    
  • The bottom layer of HashSet is implemented by HashMap, while the bottom layer of HashMap is implemented by array + linked list + red black tree

    public HashSet() {
        map = new HashMap<>();
    }
    

Set common methods

Like the List interface, the Set interface is also a sub interface of the Collection. Therefore, the common methods are the same as the Collection interface

Iterative method

  • You can use iterators
  • Enhanced for loop (essentially an iterator)

Set has no index, so it cannot be iterated with ordinary index for loop

Why can't the same element be added

  • The bottom layer of HashSet is HashMap

  • When adding an element, first get the hash value, and then turn it into an index

  • Find the storage data table table and see whether the index position has stored elements. If not, it will be directly added to the index position

  • If there are elements in the index position, the equals comparison will be called. If the comparison results are the same, the addition will be abandoned. Otherwise, the elements will be added after the linked list of the index position

  • In jdk8, if the length of the linked list is equal to 8 and the length of the array table is equal to 64, it will be converted to a red black tree

    Add element source code analysis

        Set set = new HashSet();
        set.add("tom");
        set.add("jack");
        set.add("jack");
    
  • Execute HashSet()

    public HashSet() {
        map = new HashMap<>();
    }
    
  • Execute the add () method

    public boolean add(E e) {
        // e = "tom"
        return map.put(e, PRESENT)==null;    //(static) PRESENT=new Object()
    }
    
  • Execute the put() method. If the return value is empty, it means that the location is empty and the object can be placed. If the return value is not empty, it means that there is an object in the location and its value is equal to that of the object, and the object cannot be placed

    public V put(K key, V value) { 
        //Key = "Tom" value = present (present has no practical meaning and occupies space)
        return putVal(hash(key), key, value, false, true);
    }
    
  • Execute the hash () method to get the hash value corresponding to the key, not the hashcode value.

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);  //Get the hashcode value, and then move 16 bits to the right without sign to prevent conflict
    }
    
  • Execute the putVal () method to the hash value of the key

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;  //Define auxiliary variables
        //If the current tab is empty or the size is 0, the tab array reaches 16 for the first expansion
        if ((tab = table) == null || (n = tab.length) == 0)  //table is the array length, an attribute of HashMap
            n = (tab = resize()).length; 
        //According to the hash value obtained from the key, calculate the index position where the key should be placed in the table, and assign this position object to p
        //If p is empty, it means that there is no data stored in the index location. Create a node and save the value
        if ((p = tab[i = (n - 1) & hash]) == null) 
            tab[i] = newNode(hash, key, value, null);
        //If p is not empty, it indicates that there is data at the index position
        else {
            Node<K,V> e; K k;
             //If the first element of the linked list corresponding to the current index position is equal to the hash value of the key to be added
            //In addition, if the current node object and key are the same object, or if equals is equal, equals is rewritten by the programmer
            //You cannot join
            if (p.hash == hash && 
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            //Then judge whether p is a red black tree
            //If it is a red black tree, call the putTreeVal () method to add
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            //If the location is already a linked list, use the for loop to determine whether there is a repetition
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        //After adding, judge whether the length of the linked list reaches 8. If so, the linked list at this position will be converted to red black tree operation
                       //However, the treeifyBin method will judge whether the length of the table array reaches 64. Otherwise, the table array will be expanded first, and the object will still be placed behind the linked list (at this time, the length of the linked list has exceeded 8)
                        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;
        
        //Determine whether capacity expansion is required
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
    

HashSet capacity expansion mechanism

  • The HashMap is at the bottom of the HashSet. When it is added for the first time, the table array is expanded to 16, and the threshold is 16 * the loadFactor is 0.75 = 12. Here, 12 is not the length of the table, but the total number of elements in the HashSet
  • If the number of elements reaches 12, the table array will double to 32, and the new critical value is 32 * 0.75 = 24, and so on
  • In jdk8, if the number of elements in a linked list reaches YREEIFY_THRESHOLD (8 by default), the red black tree conversion operation will be started. However, when converting to the red black tree treeifyBin() method, it will first judge whether the table reaches 64. If it reaches 64, it will be converted to the red black tree. Before reaching 64, expand the capacity of the table array first, and the object will still be placed behind the linked list (at this time, the length of the linked list has exceeded 8)

LinkedHashSet

LinkedHashSet features

  • LinkedHashSet is a subclass of HashSet. The underlying layer is LinkedHashMap. The underlying layer maintains an array + two-way linked list
  • The LinkedHashSet element determines the storage location of the element according to the hashcode value. At the same time, the linked list is used to maintain the element order, so that the element insertion and output order are consistent
  • LinkedHashSet does not allow inserting duplicate elements

TreeSet

characteristic

  • The bottom layer is TreeMap

  • When created with a parameterless constructor, dictionary sorting is used by default

    TreeSet treeSet = new TreeSet();
    treeSet.add("jack");
    treeSet.add("tom");
    treeSet.add("lucy");
    treeSet.add("marry");
    System.out.println(treeSet);
    
    Output:[jack, lucy, marry, tom]
    
  • Using the Comparator builder, you can change the collation

    TreeSet treeSet = new TreeSet(new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            //According to the dictionary from small to large, the sorting order can be changed by changing the order of o1 and o2
            return ((String)o2).compareTo((String)o1);
        }
    });
    treeSet.add("jack");
    treeSet.add("tom");
    treeSet.add("lucy");
    treeSet.add("marry");
    System.out.println(treeSet);
    
    Output:[tom, marry, lucy, jack]
    
  • If you sort by string length, you cannot add strings of the same length

    TreeSet treeSet = new TreeSet(new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            return ((String)o2).length()-((String)o1).length();
        }
    });
    treeSet.add("jack");
    treeSet.add("tom");
    treeSet.add("lucy");  //Same length, cannot add
    treeSet.add("marry");
    System.out.println(treeSet);
    
    Output:[marry, jack, tom]
    

Map

HashMap

HashMap features (JDK8)

  • The Map structure is a key value pair

  • key and value can be data (object s) of any reference type, encapsulated in the node node

    Map<Object, Object> map = new HashMap<>();
    
  • Duplicate keys cannot be added (essentially hashcode). When the same key is added repeatedly, the value in the key will be replaced, so the key can only be null at one time

  • Duplicate value values can be added, so multiple values can be added to be null

  • A pair of k-v is placed in the node node in the HashMap, and the node implements the Entry interface

  • Entry provides getKey () and getValue () methods for traversal convenience

  • Like HashSet, the mapping order is not guaranteed, because the bottom layer is stored in the form of hash table, and the bottom layer of HashMap (array + linked list + red black tree)

  • HashMap does not achieve synchronization, so it is thread unsafe. The method does not perform synchronization and mutual exclusion

Common methods of HashMap interface

  • Put (object key, object value): adds a key value pair element
  • remove (object key): removes the element whose key value is key and returns the object
  • Get (object key): get the object whose key value is key
  • Size (): get the map size
  • Clear (): clear the map
  • containsKey (object key): judge whether the object with key value exists
  • containsValue (object value): judge whether the object with value value exists

Six traversal methods of HashMap

Map map = new HashMap();
map.put("A", "a");
map.put("B", "b");
map.put("C", "c");
map.put("D", "d");
  • First take out all the keys, save the keys in the set, and then take out the corresponding value through the key

    Set keySet = map.keySet();
    //(1) Enhanced for
    for (Object key : keySet) {
        System.out.println(map.get(key));
    }
    //(2) Iterator
    Iterator iterator = keySet.iterator();
    while(iterator.hasNext()){
        Object next = iterator.next();
        System.out.println(next);
    }
    
  • Take out all value s and put them in the Collection

    Collection values = map.values();
    //(1) Enhanced for
    for (Object value : values) {
        System.out.println(value);
    }
    //(2) Iterator
    Iterator iterator = values.iterator();
    while(iterator.hasNext()){
        Object next = iterator.next();
        System.out.println(next);
    }
    
  • Get k-y through EntrySet

    Set entrySet = map.entrySet();
    //(1) Enhanced for
    for (Object entry : entrySet) {
        //Turn entry down to Map.Entry
        Map.Entry m = (Map.Entry) entry;
        System.out.println(m.getKey());
        System.out.println(m.getValue());
    }
    
    //iterator 
    Iterator iterator = entrySet.iterator();
    while (iterator.hasNext()) {
        Object entry = iterator.next();
        //Turn entry down to Map.Entry
        Map.Entry m = (Map.Entry) entry;
        System.out.println(m.getKey());
        System.out.println(m.getValue());
    }
    

The capacity expansion mechanism of HashMap is exactly the same as that of HashSet

Hashtable

Hashtable features

  • Neither key nor value can be empty

    public synchronized V put(K key, V value) {
        // Make sure the value is not null
        if (value == null) {
            throw new NullPointerException();
        }
    
  • Thread safety

  • The basic usage is the same as HashMap

  • Underlying structure: array

Hashtable infrastructure

  • The bottom layer is an array. The Hashtable internal class Entry [], the initialization size is 11
  • threshold=11*0.75=8

Comparison between Hashtable and HashMap

Thread safe (synchronous)efficiencyAllow null keys and null values
HashtablesecurityLowernot allow
HashMapunsafehighallow

Properties

Basic introduction

  • The Properties class inherits the Hashtable and implements the Map interface. It also uses key value pairs to save data. Key value pairs cannot be null
  • Similar to Hashtable
  • Properties can also be used in the xxx.properties file to load data into the properties class object, read and modify it
  • xxx.properties is usually used for configuration files

TreeMap

  • When created with a parameterless constructor, dictionary sorting is used by default

    TreeMap treeMap = new TreeMap();
    treeMap.add("jack");
    treeMap.add("tom");
    treeMap.add("lucy");
    treeMap.add("marry");
    System.out.println(treeMap);
    
    Output:[jack, lucy, marry, tom]
    
  • Using the Comparator builder, you can change the collation

    TreeMap treeMap = new TreeMap(new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            //According to the dictionary from small to large, the sorting order can be changed by changing the order of o1 and o2
            return ((String)o2).compareTo((String)o1);
        }
    });
    treeMap.add("jack");
    treeMap.add("tom");
    treeMap.add("lucy");
    treeMap.add("marry");
    System.out.println(treeMap);
    
    Output:[tom, marry, lucy, jack]
    
  • If you sort by string length, you cannot add strings of the same length

    TreeMap treeMap = new TreeMap(new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            return ((String)o2).length()-((String)o1).length();
        }
    });
    treeMap.add("jack");
    treeMap.add("tom");
    treeMap.add("lucy");  //Same length, cannot add
    treeMap.add("marry");
    System.out.println(treeMap);
    
    Output:[marry, jack, tom]
    

How to select a collection

Collections tool class

Collections is a tool class that operates on collections such as Set, List, and Map

Collections provides a series of static methods to sort, query and modify collection elements

Sorting operations (all static methods)

  • reverse (list): element inversion

    List list = new ArrayList();
    list.add("tom");
    list.add("jack");
    list.add("king");
    System.out.println(list);
    Collections.reverse(list); //Element inversion
    System.out.println(list);
    
    Output:[tom, jack, king]
         [king, jack, tom]
    
  • Sort (list): sort by dictionary by default

    List list = new ArrayList();
    list.add("tom");
    list.add("jack");
    list.add("king");
    System.out.println(list);
    Collections.sort(list);
    System.out.println(list);
    
    Output:[tom, jack, king]
         [jack, king, tom]
    
  • Sort (list, Comparator com): custom sort

    List list = new ArrayList();
    list.add("tom");
    list.add("jack");
    list.add("kinging");
    System.out.println(list);
    Collections.sort(list, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            //Sort by length
            return ((String) o2).length() - ((String) o1).length();
        }
    });
    System.out.println(list);
    
    Output:       [tom, jack, kinging]
         After sorting:[kinging, jack, tom]
    
  • swap (list, list, int i, int j): exchange the specified two location elements

    List list = new ArrayList();
    list.add("tom");
    list.add("jack");
    list.add("king");
    System.out.println(list);
    Collections.swap(list,0,2);
    System.out.println(list);
    
    Output:[tom, jack, king]
         [king, jack, tom]
    

Find, replace

  • max (Collection c): the maximum value is given in natural order

    List list = new ArrayList();
    list.add("tom");
    list.add("jack");
    list.add("king");
    System.out.println(Collections.max(list));
    
    Output: tom
    
  • max (Collection c, Comparator com): Custom return value

    List list = new ArrayList();
    list.add("tom");
    list.add("jack");
    list.add("kinging");
    Object max = Collections.max(list, new Comparator() {
        @Override
        public int compare(Object o1, Object o2) {
            //Custom, returns the element with the largest length
            return ((String) o1).length() - ((String) o2).length();
        }
    });
    System.out.println(max);
    
    Output: kinging
    

Topics: Java set