Java Basics Review No. 4 - Collection List, Map and Set

foreword

In the last article , I reviewed the three major features of Java: encapsulation, inheritance and polymorphism. This article will introduce the next set.

Collection introduction

When we develop Java programs, in addition to the most commonly used basic data types and String objects, we often use collection-related classes.
Collection classes store references to objects, not the objects themselves. For the convenience of expression, we call the objects in the collection the references to the objects in the collection.
There are three main types of collections: List, Set, and Map.
The relationship between them can be represented by the following diagram:

write picture description here

Note: Map is not a subclass of collections, but they are fully integrated into collections!

List

The List interface is inherited from the Collection interface and defines an ordered collection that allows duplicates. Not only does this interface handle parts of the list, it also adds position-oriented operations.

Generally speaking, the List we mainly use in single thread is ArrayList and LinkedList to implement, multi thread is to use Vector or use Collections.sychronizedList to decorate a collection.
The three are explained as follows:

  • ArrayList: Internally implemented through arrays, it allows fast random access to elements. When inserting or deleting elements from the middle of the ArrayList, the array needs to be copied, moved, and the cost is relatively high. Therefore, it is suitable for random lookups and traversals, not for insertions and deletions.
  • LinkedList: It stores data in a linked list structure, which is very suitable for dynamic insertion and deletion of data. The random access and traversal speed are relatively slow. In addition, it also provides methods that are not defined in the List interface, which are specially used to operate the header and footer elements, which can be used as stacks, queues and bidirectional queues.
  • Vector: Implemented through an array, the difference is that it supports thread synchronization. Access speed ArrayList is slow.

They are used as follows:

List list1 = new ArrayList();
List list2 = new LinkedList();
List list3 = new Vector();
List list4=Collections.synchronizedList(new ArrayList())

After understanding their usage, let's take a look at why using ArrayList is faster than LinkedList query, and using LinkedList is faster than ArrayList adding and deleting!
The following code is also used here to illustrate, and Vector is also compared by the way.

Code sample:

    private final static int count=50000;

    private static ArrayList arrayList = new ArrayList<>();  
    private static LinkedList linkedList = new LinkedList<>();  
    private static Vector vector = new Vector<>();  


    public static void main(String[] args) {
        insertList(arrayList);
        insertList(linkedList);
        insertList(vector);

        System.out.println("--------------------");

        readList(arrayList);
        readList(linkedList);
        readList(vector);

        System.out.println("--------------------");

        delList(arrayList);
        delList(linkedList);
        delList(vector);
    }

    private  static void insertList(List list){   
         long start=System.currentTimeMillis();   
         Object o = new Object();   
         for(int i=0;i<count;i++){   
             list.add(0, o);   
         }
        System.out.println(getName(list)+"插入"+count+"条数据,耗时:"+(System.currentTimeMillis()-start)+"ms");
     }   

    private  static void readList(List list){   
         long start=System.currentTimeMillis();   
         Object o = new Object();   
         for(int i = 0 ; i < count ; i++){  
                list.get(i);  
            }
        System.out.println(getName(list)+"查询"+count+"条数据,耗时:"+(System.currentTimeMillis()-start)+"ms");
     }  


    private  static void delList(List list){   
         long start=System.currentTimeMillis();   
         Object o = new Object();   
         for(int i = 0 ; i < count ; i++){  
             list.remove(0);   
            }
        System.out.println(getName(list)+"删除"+count+"条数据,耗时:"+(System.currentTimeMillis()-start)+"ms");
     }  

    private static String getName(List list) {  
        String name = "";  
        if(list instanceof ArrayList){  
            name = "ArrayList";  
        }  
        else if(list instanceof LinkedList){  
            name = "LinkedList";  
        }  
        else if(list instanceof Vector){  
            name = "Vector";  
        }  
        return name;  
    }  

Output result:

    ArrayList插入50000条数据,耗时:281ms
    LinkedList插入50000条数据,耗时:2ms
    Vector插入50000条数据,耗时:274ms
    --------------------
    ArrayList查询50000条数据,耗时:1ms
    LinkedList查询50000条数据,耗时:1060ms
    Vector查询50000条数据,耗时:2ms
    --------------------
    ArrayList删除50000条数据,耗时:143ms
    LinkedList删除50000条数据,耗时:1ms
    Vector删除50000条数据,耗时:137ms

From the above results, we can clearly see the difference between ArrayList and LinkedList in addition, deletion and query performance.

In collections, we generally use to store data. However, sometimes when there are multiple sets, we want to do the operations of collection, intersection, difference and union of these sets. In List, these methods have been encapsulated, we do not need to write the corresponding code, just use it directly.
The code example is as follows:

/**
     * 合集
     * @param ls1
     * @param ls2
     * @return
     */
    private static List<String> addAll(List<String> ls1,List<String>ls2){
        ls1.addAll(ls2);
        return ls1;
    }

    /**
     * 交集 (retainAll 会删除 ls1在ls2中没有的元素)
     * @param ls1
     * @param ls2
     * @return
     */
    private static List<String> retainAll(List<String> ls1,List<String>ls2){
        ls1.retainAll(ls2);
        return ls1;
    }

    /**
     * 差集 (删除ls2中没有ls1中的元素)
     * @param ls1
     * @param ls2
     * @return
     */
    private static List<String> removeAll(List<String> ls1,List<String>ls2){
        ls1.removeAll(ls2);
        return ls1;
    }

    /**
     * 无重复的并集 (ls1和ls2中并集,并无重复)
     * @param ls1
     * @param ls2
     * @return
     */
    private static List<String> andAll(List<String> ls1,List<String>ls2){
        //删除在ls1中出现的元素
        ls2.removeAll(ls1);
        //将剩余的ls2中的元素添加到ls1中
        ls1.addAll(ls2);
        return ls1;
    }

Of course, it is often used to traverse the List.
There are three main methods for traversing List arrays, ordinary for loop, enhanced for loop (appeared after jdk1.5), and Iterator (iterator).

Code sample:

     List<String> list=new ArrayList<String>();
     list.add("a");
     list.add("b");
     list.add("c");

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

     for (String str : list) {  
         System.out.println(str);
     }

     Iterator<String> iterator=list.iterator();
     while(iterator.hasNext())
     {
         System.out.println(iterator.next());
     }

Note: There is little difference between the ordinary for loop and the enhanced for loop. The main difference is that the ordinary for loop can obtain the subscript of the set, but the enhanced for loop cannot. However, the enhanced for loop is written. If you do not need to obtain the subscript of a specific set, it is recommended to use the enhanced for loop. As for the Iterator (iterator), it is also impossible to obtain the data subscript, but this method does not need to worry about the length of the collection changing during the traversal process. That is, the collection is added and deleted when it is traversed.

In <Alibaba Java Development Manual>中,对于集合操作也有这种说明。

Do not perform remove/add operations on elements in a foreach loop. Please use the Iterator method to remove elements. If you operate concurrently, you need to lock the Iterator object.

So why not use a foreach loop to remove / add elements?
We can simply do the verification here.

Code sample:

    List<String> list = new ArrayList<String>();
         list.add("1");
         list.add("2");
         System.out.println("list遍历之前:"+list);
         for (String item : list) {
           if ("2".equals(item)) {
            list.remove(item);
            //如果这里不适用break的话,会直接报错的
            break; 
         }
       } 
        System.out.println("list遍历之后:"+list);

        List<String> list1 = new ArrayList<String>();
         list1.add("1");
         list1.add("2");
        System.out.println("list1遍历之前:"+list1);
         Iterator<String> iterator = list1.iterator();
         while (iterator.hasNext()) {
             String item = iterator.next();
             if ("2".equals(item)) {
                 iterator.remove();
             }
         }
         System.out.println("list1遍历之后:"+list1);

Output result:

    list遍历之前:[1, 2]
    list遍历之后:[1]
    list1遍历之前:[1, 2]
    list1遍历之后:[1]

注意:上述代码中,在对list进行for循环遍历的时候,加了break,

In the above examples, the data we want is printed correctly, but in the foreach loop, I added a break . If no break is added, ConcurrentModificationException will be thrown directly!

Map

The Map interface is not an inheritance of the Collection interface . Map provides key to value mapping. A Map cannot contain the same key, and each key can only map one value. The Map interface provides three sets of views. The contents of the Map can be regarded as a set of key sets, a set of value sets, or a set of key-value mappings.

The Map interface is mainly implemented by the classes HashMap, TreeMap, LinkedHashMap, Hashtable and ConcurrentHashMap.
They are explained as follows:

  • HashMap : The key of HashMap is obtained according to HashCode, so the corresponding value can be quickly obtained according to the key. However, its key object cannot be repeated. It allows the key to be Null, but there can only be one record at most, but it can allow the value of multiple records to be Null. Because HashMap is not thread safe, it is very efficient.
  • TreeMap : You can sort the saved records according to the key, the default is the ascending order of the key value (natural order). You can also specify a sorted comparator. When traversing the TreeMap with an Iterator, the resulting records are sorted. It also does not allow null key values ​​and is not thread safe.
  • LinkedHashMap : LinkedHashMap is basically the same as HashMap. However, the difference is that LinkedHashMap maintains a double-linked list, and the data in it can be read out in the order in which it was written. LinkedHashMap can be considered as HashMap+LinkedList. That is, it not only uses HashMap to operate the data structure, but also uses LinkedList to maintain the order of inserting elements. It is also not thread safe.
  • Hashtable : Hashtable is similar to HashMap and can be said to be a thread-safe version of HashMap. However it is not allowed to record keys or values ​​that are null. Because it supports thread synchronization and is thread-safe, it also causes Hashtale to be inefficient.
  • ConcurrentHashMap : ConcurrentHashMap was newly introduced in Java 1.5 as an alternative to Hashtable. Using lock segmentation technology to ensure thread safety can be regarded as an upgraded version of Hashtable.

At work, the Map we use the most should be HashMap. However, sometimes when using Map, it is necessary to sort in natural order. Here we can use TreeMap without having to implement this function ourselves. The use of TreeMap is similar to that of HashMap. However, it should be noted that TreeMap does not allow key to be null. Here is a brief introduction to the use of TreeMap.

Code sample:

    Map<String,Object> hashMap=new HashMap<String,Object>();
        hashMap.put("a", 1);
        hashMap.put("c", 3);
        hashMap.put("b", 2);
        System.out.println("HashMap:"+hashMap);

        Map<String,Object> treeMap=new TreeMap<String,Object>();
        treeMap.put("a", 1);
        treeMap.put("c", 3);
        treeMap.put("b", 2);
        System.out.println("TreeMap:"+treeMap);

Output result:

    HashMap:{b=2, c=3, a=1}
    TreeMap:{a=1, b=2, c=3}

It can be seen from the above that HashMap is unordered and TreeMap is ordered.

When using Map, Map is also traversed. Generally, there are three ways to traverse the key and value of Map:
the first is to traverse through Map.keySet; the
second is to traverse through Map.entrySet using iterator;
the third is to traverse through Map.entrySet.
Use as follows:

 Map<String, String> map = new HashMap<String, String>();
 for (String key : map.keySet()) {
       System.out.println("key= "+ key + " and value= " + map.get(key));
      }
  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
    while (it.hasNext()) {
       Map.Entry<String, String> entry = it.next();
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }


      for (Map.Entry<String, String> entry : map.entrySet()) {
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }

If you only want to get the value in the Map, you can use foreach to traverse Map.values().

for (String v : map.values()) {
     System.out.println("value= " + v);
 }

In the above traversal, we use the first Map.keySet the most, because it is relatively simple to write. However, when the capacity is large, it is recommended to use the third one, and the efficiency will be higher!

Set

Set is a Collection that does not contain duplicate elements, that is, any two elements e1 and e2 have e1.equals(e2)=false, and Set has at most one null element. Because Set is an abstract interface, it is not possible to directly instantiate a set object. Set s = new Set()This spelling is wrong.

The Set interface is mainly implemented by HashSet, TreeSet and LinkedHashSet.
They are simply used as follows:

Set hashSet = new HashSet();
Set treeSet = new TreeSet();
Set linkedSet = new LinkedHashSet();

Because Set cannot have duplicate elements, it is often used to deduplicate. For example, there are two pieces of the same data in a list set, and if you want to remove one, you can use the mechanism of Set to remove duplicates.
Code example:

    public static void set(){
        List<String> list = new ArrayList<String>();
        list.add("Java");
        list.add("C");
        list.add("C++");
        list.add("JavaScript");
        list.add("Java");
        Set<String> set = new HashSet<String>();
        for (int i = 0; i < list.size(); i++) {
            String items = list.get(i);
            System.out.println("items:"+items);
            if (!set.add(items)) {
                System.out.println("重复的数据: " + items);
            }
        }
        System.out.println("list:"+list);
    }

Output result:

items:Java
items:C
items:C++
items:JavaScript
items:Java
重复的数据: Java
list:[Java, C, C++, JavaScript, Java]

Note: If the object is to be deduplicated, the equals and hashcode methods in the set need to be rewritten.

Summarize

The summary of List, Map, and Set in the collection is as follows:

  • List:List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector>

    • ArrayList: Not thread-safe, suitable for random search and traversal, not suitable for insertion and deletion.
    • LinkedList : Not thread safe, suitable for insertion and deletion, not suitable for lookup.
    • Vector : thread safe. But not recommended.
  • Map: A class for a key-to-value mapping.

    • HashMap: Not thread safe, both keys and values ​​allow null values ​​to exist.
    • TreeMap: Not thread safe, traverse keys in natural or custom order.
    • LinkedHashMap: Non-thread-safe, maintains a double-linked list, and can read the data in it in the order in which it was written. Writing is stronger than HashMap, and adding and deleting is worse than HashMap.
    • Hashtable: thread-safe, keys and values ​​are not allowed to have null values. Not recommended.
    • ConcurrentHashMap: thread-safe, an upgraded version of Hashtable. Multi-threaded use is recommended.
  • Set: Duplicate data is not allowed. Retrieval efficiency is low, deletion and insertion efficiency is high.

    • HashSet: non-thread safe, unordered, data can be null.
    • TreeSet: Not thread-safe, ordered, and the data cannot be null.
    • LinkedHashSet: non-thread-safe, unordered, data can be null. Writing is stronger than HashSet, and adding and deleting is worse than HashSet.

    This is the end of this article, thank you for reading.

版权声明:
作者:虚无境
博客园出处:http://www.cnblogs.com/xuwujing
CSDN出处:http://blog.csdn.net/qazwsxpcm    
个人博客出处:http://www.panchengming.com
原创不易,转载请标明出处,谢谢!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325633197&siteId=291194637