After a descriptive introduction, today entered the List, Set, Map the last link, first on the mind Map

Topic 1: What is a Java Collections Framework? What are the advantages?

There are collections in every programming language, and initially Java contained only Vector, Stack, HashTable, and Array collections. With the widespread use of collections, a collection framework that encompasses all collections interfaces, implementations, and algorithms has been in place since Java1.2.

The advantages of using a collection framework are as follows:

  1. Reduce development costs by using core collection classes rather than implementing our own.
  2. With the use of rigorously tested collection framework classes, code quality improves.
  3. You can reduce your code maintenance costs by using the collection classes that come with the JDK
  4. Reusability and operability.

Topic 2: What are the characteristics of generics in collections frameworks?

  1. Java1.5 introduced generics, which are heavily used by all collection interfaces and implementations.
  2. Generics allow us to provide a collection with a containable object type, so if you add any elements of other types, it will report an error at compile time
  3. This avoids a ClassCastException at runtime
  4. Generics also keep the code clean, and we don’t need to use explicit conversions and instanceOf operators
  5. It benefits the runtime because no type-checking bytecode instructions are generated.

List, Set, Map, Map

  1. First, they are all part of the Java Collections framework, and second, all three are interfaces
  2. List and Set inherit from the Collection interface, Map does not
  3. The biggest difference between a List implementation class and a Set implementation class is whether elements can be repeated. A List implementation class must be an ordered collection, while a Set implementation class can be unordered or ordered.
  4. Here the order and disorder are defined relative to the access order, the order of deposit is equal to the order of take out is considered to be ordered, and the unordered Set implementation class also has its own internal definition of the order, such as HashSet
  5. List includes ArrayList, Vector and LinkedList
    1. ArrayList and Vector are implemented based on arrays, and LinkedList is implemented based on bidirectional lists
    2. Only Vector is thread-safe
    3. Different data structures for arrays and bidirectionally linked lists result in different performance (see examples below)
  6. Set mainly has HashSet, TreeSet, LinkedHashSet three commonly used implementation classes, the difference lies in
    1. HashSet is based on hash table, TreeSet is based on binary tree, LinkedHashSet is inherited from HashSet, which is based on hash table and introduces bidirectional linked list
    2. None of them are thread safe
    3. The three data structures can also lead to performance differences
  7. The List implementation classes both implement the List interface and inherit from the AbstractList abstract class, while the Set implementation classes both implement the Set interface and inherit from the AbstractSet abstract class, so they each have their own Set of CRUD operations of the same name
  8. The Map interface does not inherit from the Collection interface because it makes no sense. The essence of an interface is a set of code specifications, the essence of a Map is a key-value pair, and the essence of a Collection is a set of objects.
  9. Map includes HashMap, TreeMap, and LinkedHashMap
    1. HashMap is based on hash table, TreeMap is based on binary tree, and LinkedHashMap is inherited from HashMap, which introduces bidirectional linked list on the basis of hash table
    2. None of them are thread safe
    3. The three data structures can also lead to performance differences
  10. The three implementation classes of Set and Map have similar properties and differences, because the underlying classes of HashSet, TreeSet and LinkedHashSet are HashMap, TreeMap and LinkedHashMap respectively.

Field measurement: performance test

Here we separately carry out single-thread performance tests for implementation classes under the same interface

ArrayList, Vector, LinkedList

public class ListDemo {


    public static void main(String[] args) {
        // Test only one implementation class at a time
        List<Integer> list = new ArrayList<>();
        //List<Integer> list = new Vector<>();
        //List<Integer> list = new LinkedList<>();


        test(list);

    }

    /** ** entry **@param list
     */
    public static void test(List<Integer> list) {
        testAddTime(list, 1000000);
        testIndexUpTime(list);
        testForEachTime(list);
        testIteratorTime(list);
        testIndexDownTime(list);
        testReadRandomTime(list);
        testRandomDelTime(list);
        testRandomAddTime(list);
        testRandomSetTime(list);
    }

    /** * Add tests ** in sequence@param list
     */
    public static void testAddTime(List<Integer> list, int size) {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            list.add(i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "Insert" + size + Total time of each element: + (endTime - startTime) + "ms");
    }

    /** * Iterator traverses the test **@param list
     */
    public static void testIteratorTime(List<Integer> list) {
        long startTime = System.currentTimeMillis();
        Iterator<Integer> it = list.iterator();
        while (it.hasNext()) {
            Integer integer = it.next();
            / / null traverse
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "Iterator traversal time: + (endTime - startTime) + "ms");
    }

    /** * ForEach traversal test **@param list
     */
    public static void testForEachTime(List<Integer> list) {
        long startTime = System.currentTimeMillis();
        for (Integer i : list) {
            / / null traverse
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "ForEach traverse time:" + (endTime - startTime) + "ms");
    }

    /** * index increments traversal test **@param list
     */
    public static void testIndexUpTime(List<Integer> list) {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < list.size(); i++) {
            / / air circulation
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + Incremental index traversal time: + (endTime - startTime) + "ms");
    }

    /** * index decrement traversal test **@param list
     */
    public static void testIndexDownTime(List<Integer> list) {
        long startTime = System.currentTimeMillis();
        for (int i = list.size() - 1; i > 0; i--) {
            / / air circulation
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "Decrement index traversal time:" + (endTime - startTime) + "ms");
    }

    /** * Random read test **@param list
     */
    public static void testReadRandomTime(List<Integer> list) {
        long startTime = System.currentTimeMillis();
        Random random = new Random();
        Integer integer = 0;
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(list.size());
            integer = list.get(randomInt);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "10,000 random reads time:" + (endTime - startTime) + "ms");
    }

    /** * Randomly delete test **@param list
     */
    public static void testRandomDelTime(List<Integer> list) {
        long startTime = System.currentTimeMillis();
        Random random = new Random();
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(list.size());
            list.remove(randomInt);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "Time to randomly delete 10,000 elements:" + (endTime - startTime) + "ms");
    }

    /** * randomly insert objects *@param list
     */
    public static void testRandomAddTime(List<Integer> list){
        long startTime = System.currentTimeMillis();
        Random random = new Random();
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(list.size());
            list.add(randomInt,randomInt);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "Time to randomly insert 10,000 elements:" + (endTime - startTime) + "ms");
    }

    /** * Randomly change the object *@param list
     */
    public static void testRandomSetTime(List<Integer> list){
        long startTime = System.currentTimeMillis();
        Random random = new Random();
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(list.size());
            list.set(randomInt,randomInt);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(list.getClass() + "Time to randomly change 10,000 elements:" + (endTime - startTime) + "ms"); }}Copy the code

Based on the single-variable test method, where I change only one variable at a time (same environment, same code, different implementation class only), I get the following three results

To be honest, I was a little surprised to see this result, since the results of my previous articles were based on theory prior to this official test, but the results of this test showed that LinkedList’s performance was no better than ArrayList’s. And it’s still in my collection of samples were transferred to the array, 1 million, 5 million samples were from the beginning I directly on, at the time of test to LinkedList randomization, I thought my computer card, a half-day did not give a result, test for 3 times in a row, until I put the samples were transferred to 1 million, to see the results of randomization, I then tested it five times in a row with a million samples and found that ArrayList beat LinkedList.

HashSet, TreeSet, LinkedHashSet

public class SetDemo {


    public static void main(String[] args) {
        / / the random class
        Random random = new Random();
        // 1 million samples
        int size = 1000000;
        // Test only one implementation class at a time
        Set<Integer> set = new HashSet<>();
        //Set<Integer> set = new TreeSet<>();
        //Set<Integer> set = new LinkedHashSet<>();

        // Sequential insertion
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            set.add(i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(set.getClass() + "Insert" + size + Total time of each element: + (endTime - startTime) + "ms");

        // iterator traversal
        startTime = System.currentTimeMillis();
        Iterator<Integer> it = set.iterator();
        while (it.hasNext()) {
            / / null traverse
            Integer integer = it.next();
        }
        endTime = System.currentTimeMillis();
        System.out.println(set.getClass() + "Iterator traversal total time:" + (endTime - startTime) + "ms");

        / / ForEach traversal
        startTime = System.currentTimeMillis();
        for (Integer i : set) {
            / / air circulation
        }
        endTime = System.currentTimeMillis();
        System.out.println(set.getClass() + "ForEach traversal total time: + (endTime - startTime) + "ms");

        // Random update (set does not repeat, insert small update)
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(set.size());
            set.add(randomInt);
        }
        endTime = System.currentTimeMillis();
        System.out.println(set.getClass() + "Total time of randomly updating 10000 elements:" + (endTime - startTime) + "ms");

        // Delete randomly
        startTime = System.currentTimeMillis();
        Integer integer = 0;
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(set.size());
            set.remove(randomInt);
        }
        endTime = System.currentTimeMillis();
        System.out.println(set.getClass() + "Total time for randomly deleting 10000 elements:" + (endTime - startTime) + "ms"); }}Copy the code

The results fit the assumptions of previous articles, with HashSet inserts being the fastest, LinkedHashSet look-up the fastest, and TreeSet being a moderate choice.

HashMap, TreeMap, LinkedHashMap

public class MapDemo {


    public static void main(String[] args) {
        / / the random class
        Random random = new Random();
        String emptyString = "";
        // 1 million samples
        int size = 1000000;
        // Test only one implementation class at a time
        Map<String, String> map = new HashMap<>();
        //Map<String, String> map = new TreeMap<>();
        //Map<String, String> map = new LinkedHashMap<>();

        // Sequential insertion
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            map.put(i + emptyString, i + emptyString);
        }
        long endTime = System.currentTimeMillis();
        System.out.println(map.getClass() + "Insert" + size + Total time of each element: + (endTime - startTime) + "ms");

        // Random fetch
        startTime = System.currentTimeMillis();
        String valueStr = "";
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(map.size());
            valueStr = map.get(randomInt + emptyString);
        }
        endTime = System.currentTimeMillis();
        System.out.println(map.getClass() + "10,000 random reads time:" + (endTime - startTime) + "ms");

        // Delete randomly
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            int randomInt = random.nextInt(map.size());
            map.remove(randomInt + emptyString);
        }
        endTime = System.currentTimeMillis();
        System.out.println(map.getClass() + "Randomly delete 10,000 time:" + (endTime - startTime) + "ms");

        / / keySet
        startTime = System.currentTimeMillis();
        Set<String> stringSet = map.keySet();
        endTime = System.currentTimeMillis();
        System.out.println(map.getClass() + "KeySet conversion time:" + (endTime - startTime) + "ms");

        / / values
        startTime = System.currentTimeMillis();
        Collection<String> values = map.values();
        endTime = System.currentTimeMillis();
        System.out.println(map.getClass() + "Converting values takes time:" + (endTime - startTime) + "ms"); }}Copy the code

Doesn’t seem to make much of a difference except that TreeMap inserts slightly less efficiently

summary

At this stage, the Java container is almost finished. In fact, the test code can be further improved. For example, the memory can be checked to determine the resource consumption of different containers, and then the sample size can be increased to 3 million or 5 million. I don’t think anyone would take that many objects and put them in one container at a time, so I think a million samples is enough, and then you have complex objects as container elements that you can test. I’m using the single variable principle here, so I can’t test it all in one article.

The test code is as follows: github.com/MagicH666/J…