Java Collections series (four): HashMap, Hashtable, LinkedHashMap, TreeMap to use and differences

This blog mainly on the Map interface 4 implementation class HashMap, the difference between Hashtable, LinkedHashMap, TreeMap to use and three.

Note: The code in this article use the JDK version 1.8.0_191

It is worth noting, Map interface is a separate interface, and not inherit the Collection interface (here is the key, frequently asked interview):

public interface Map<K,V> {
	......
}
复制代码

1. HashMap use

Map interface HashMap is the most common implementation class, Key Value store key-value pairs, HashMap, but does not guarantee the order of the elements guarantee Key must be unique.

HashMap class declaration code is as follows:

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
	......
}
复制代码

1.1 Adding elements

There are three methods of using HashMap add elements:

  1. put
  2. putIfAbsent
  3. putAll

First look to use put () method:

HashMap<String, String> platformMap = new HashMap<>();

// 添加元素
System.out.println(platformMap.put("cnblogs.com", "博客园"));
System.out.println(platformMap.put("juejin.im", "掘金"));
System.out.println(platformMap.put("map.weixin.qq.com", "微信公众号"));
System.out.println(platformMap.put("zwwhnly.com", "个人博客"));

// 添加重复的Key,没有添加成功,但是会更新Key对应的Value值
// 不过代码不会报错,而是返回已经存在Key对应的Value
System.out.println(platformMap.put("zwwhnly.com", "个人博客"));
复制代码

The output code is run is:

null

null

null

null

personal blog

The debugging code also find platformMap only four elements, but the order of elements and add different order:

It is noteworthy that last line of code platformMap.put("zwwhnly.com", "个人博客")the return value is "personal blog", that is, pre-existing Key: zwwhnly.com, corresponding Value value.

Simple modifications to this code:

System.out.println(platformMap.put("zwwhnly.com", "个人博客2"));
复制代码

Run the code again and found that the output has not changed, platformMap still four elements, but the content has changed platformMap elements:

If Key is present, undesirable Value is covered, the code can be modified to:

System.out.println(platformMap.putIfAbsent("zwwhnly.com", "个人博客2"));
复制代码

Further, the putAll the HashMap also provides a () method to add bulk element, using the following method:

HashMap<String, String> platformMap = new HashMap<>();

HashMap<String, String> majorPlatfromMap = new HashMap<>();

// 添加元素
majorPlatfromMap.put("cnblogs.com", "博客园");
majorPlatfromMap.put("juejin.im", "掘金");

HashMap<String, String> otherPlatformMap = new HashMap<>();

otherPlatformMap.put("map.weixin.qq.com", "微信公众号");
otherPlatformMap.put("zwwhnly.com", "个人博客");

otherPlatformMap.put("cnblogs.com", "博客园2");

platformMap.putAll(majorPlatfromMap);
platformMap.putAll(otherPlatformMap);
复制代码

It is noted that, due to the presence of otherPlatformMap majorPlatfromMap the same key: cnblogs.com, platformMap final value of the Key Value "cnblogs.com" is: "Park blog 2", as shown below:

1.2 Gets the element

There are two methods of using HashMap get elements:

  1. get()
  2. getOrDefault()

First look get () method of use:

System.out.println(platformMap.get("cnblogs.com"));
System.out.println(platformMap.get("csdn.com"));
复制代码

Output:

Blog Park

null

When the key is not present, the default value set if necessary, may be used getOrDefault ():

System.out.println(platformMap.getOrDefault("csdn.com", "CSDN"));
复制代码

The output of this code as above: CSDN.

1.3 Get number of the sets of elements

Get the number of elements of the HashMap methods are as follows:

System.out.println("platformMap的元素个数为:" + platformMap.size());
复制代码

1.4 Removing elements

HashMap delete elements using the following two overloaded:

public V remove(Object key) {
    Node<K,V> e;
    return (e = removeNode(hash(key), key, null, false, true)) == null ?
        null : e.value;
}

@Override
public boolean remove(Object key, Object value) {
    return removeNode(hash(key), key, value, true, true) != null;
}
复制代码

Use as follows:

System.out.println(platformMap.remove("zwwhnly.com"));
System.out.println(platformMap.remove("zwwhnly.com"));
System.out.println(platformMap.remove("map.weixin.qq.com", "微信公众号"));
System.out.println(platformMap.remove("juejin.im", "博客园"));
复制代码

The output of the above code:

personal blog

null

true

false

1.5 modify elements

HashMap modify elements using the following two overloaded:

@Override
public boolean replace(K key, V oldValue, V newValue) {
    Node<K,V> e; V v;
    if ((e = getNode(hash(key), key)) != null &&
        ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
        e.value = newValue;
        afterNodeAccess(e);
        return true;
    }
    return false;
}

@Override
public V replace(K key, V value) {
    Node<K,V> e;
    if ((e = getNode(hash(key), key)) != null) {
        V oldValue = e.value;
        e.value = value;
        afterNodeAccess(e);
        return oldValue;
    }
    return null;
}
复制代码

Use as follows:

System.out.println(platformMap.replace("cnblogs.com", "博客园:https://www.cnblogs.com/zwwhnly/"));
System.out.println(platformMap.replace("juejin.im", "掘金", "掘金:https://juejin.im/user/5c7ce730f265da2dca388167"));
复制代码

The output of the above code:

Blog Park

true

1.6 is determined whether the set is empty

HashMap is empty is determined whether to use the following:

System.out.println("isEmpty:" + platformMap.isEmpty());
复制代码

1.7 traversing element (Frequently Asked Interview)

HashMap traversing elements mainly in the following four ways:

  1. Use keySet get all Key, then traverse
  2. Use Map.entrySet get all the elements, and then use the iterator traversal
  3. Use Map.entrySet get all the elements, and then use the foreach loop iterates
  4. Direct use values ​​to get the value of all the ways you can not traverse Key

2 and 3, the manner in which, using the two kinds of traversal Set set as platformMap.entrySet()the return type of a Set is set inside the element type is Map.Entry<K,V>:

public Set<Map.Entry<K,V>> entrySet() {
    Set<Map.Entry<K,V>> es;
    return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
复制代码

Use as follows:

System.out.println("方式1:使用keySet遍历");
for (String key : platformMap.keySet()) {
    System.out.println("Key:" + key + ",Value:" + platformMap.get(key));
}

System.out.println();
System.out.println("方式2:通过Map.entrySet使用iterator遍历");
Iterator<Map.Entry<String, String>> iterator = platformMap.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, String> entry = iterator.next();
    System.out.println("Key:" + entry.getKey() + ",Value:" + entry.getValue());
}

System.out.println();
System.out.println("方式3:通过Map.entrySet使用iterator遍历");
for (Map.Entry<String, String> entry : platformMap.entrySet()) {
    System.out.println("Key:" + entry.getKey() + ",Value:" + entry.getValue());
}

System.out.println();
System.out.println("方式4:使用values遍历,使用这种方式无法遍历Key");
for (String value : platformMap.values()) {
    System.out.println(value);
}
复制代码

1.8 Empty collection

Empty the HashMap use all the elements are as follows:

platformMap.clear();
复制代码

1.9 Full Sample Code

Some, complete code explained above is as follows:

package collection;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class MapTest {
    public static void main(String[] args) {
        HashMap<String, String> platformMap = new HashMap<>();

        HashMap<String, String> majorPlatfromMap = new HashMap<>();

        // 添加元素
        majorPlatfromMap.put("cnblogs.com", "博客园");
        majorPlatfromMap.put("juejin.im", "掘金");

        HashMap<String, String> otherPlatformMap = new HashMap<>();

        otherPlatformMap.put("map.weixin.qq.com", "微信公众号");
        otherPlatformMap.put("zwwhnly.com", "个人博客");

        platformMap.putAll(majorPlatfromMap);
        platformMap.putAll(otherPlatformMap);

        System.out.println(platformMap.get("cnblogs.com"));
        System.out.println(platformMap.get("csdn.com"));
        System.out.println(platformMap.getOrDefault("csdn.com", "CSDN"));

        System.out.println("platformMap的元素个数为:" + platformMap.size());

        System.out.println(platformMap.remove("zwwhnly.com"));
        System.out.println(platformMap.remove("zwwhnly.com"));
        System.out.println(platformMap.remove("map.weixin.qq.com", "微信公众号"));
        System.out.println(platformMap.remove("juejin.im", "博客园"));

        System.out.println(platformMap.replace("cnblogs.com", "博客园:https://www.cnblogs.com/zwwhnly/"));
        System.out.println(platformMap.replace("juejin.im", "掘金", "掘金:https://juejin.im/user/5c7ce730f265da2dca388167"));

        System.out.println("isEmpty:" + platformMap.isEmpty());

        System.out.println("方式1:使用keySet遍历");
        for (String key : platformMap.keySet()) {
            System.out.println("Key:" + key + ",Value:" + platformMap.get(key));
        }

        System.out.println();
        System.out.println("方式2:通过Map.entrySet使用iterator遍历");
        Iterator<Map.Entry<String, String>> iterator = platformMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            System.out.println("Key:" + entry.getKey() + ",Value:" + entry.getValue());
        }

        System.out.println();
        System.out.println("方式3:通过Map.entrySet使用iterator遍历");
        for (Map.Entry<String, String> entry : platformMap.entrySet()) {
            System.out.println("Key:" + entry.getKey() + ",Value:" + entry.getValue());
        }

        System.out.println();
        System.out.println("方式4:使用values遍历,使用这种方式无法遍历Key");
        for (String value : platformMap.values()) {
            System.out.println(value);
        }

        platformMap.clear();
        System.out.println("isEmpty:" + platformMap.isEmpty());
    }
}
复制代码

The output is:

Blog Park

null

CSDN

PlatformMap number of elements is: 4

personal blog

null

true

false

Blog Park

true

isEmpty:false

Method 1: Use traverse keySet

Key: cnblogs.com, Value: blog Garden: www.cnblogs.com/zwwhnly/

Key: juejin.im, Value: Nuggets: juejin.im/user/5c7ce7...

Embodiment 2: Using the iterator traversal by Map.entrySet

Key: cnblogs.com, Value: blog Garden: www.cnblogs.com/zwwhnly/

Key: juejin.im, Value: Nuggets: juejin.im/user/5c7ce7...

Mode 3: Use the iterator to traverse through Map.entrySet

Key: cnblogs.com, Value: blog Garden: www.cnblogs.com/zwwhnly/

Key: juejin.im, Value: Nuggets: juejin.im/user/5c7ce7...

Mode 4: Use the values ​​traversal, using this method can not be traversed Key

Park blog: www.cnblogs.com/zwwhnly/

Nuggets: juejin.im/user/5c7ce7...

isEmpty:true

2. Hashtable use

Hashtable class that implements the Map interface is also worth noting that its methods are synchronized, that is thread-safe.

public synchronized int size() {
    return count;
}

public synchronized boolean isEmpty() {
    return count == 0;
}
复制代码

HashTable class declaration code is as follows:

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {
{
	......
}
复制代码

Can also be seen from the above code, Hashtable base class is Dictionary, the base class is AbstractMap HashMap (this is the key, often ask the interview).

Use HashMap HashTable class and essentially the same, only the modifications to the code declared at:

Hashtable<String, String> platformMap = new Hashtable<>();
Hashtable<String, String> majorPlatfromMap = new Hashtable<>();
Hashtable<String, String> otherPlatformMap = new Hashtable<>();
复制代码

3. LinkedHashMap use

LinkedHashMap Map interface implementation class is compared to the HashMap, it used to list, which can ensure insertion order, i.e., FIFO (First Input First Output FIFO).

LinkedHashMap class declaration code is as follows:

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{
	......
}
复制代码

Can also be seen from the above code, LinkedHashMap class inherits class HashMap.

Use LinkedHashMap HashMap and essentially the same class, only to modify the code at the next statement:

LinkedHashMap<String, String> platformMap = new LinkedHashMap<>();
LinkedHashMap<String, String> majorPlatfromMap = new LinkedHashMap<>();
LinkedHashMap<String, String> otherPlatformMap = new LinkedHashMap<>();
复制代码

4. TreeMap using

TreeMap is the class that implements the Map interface, it is worth noting that, in the TreeMap element is ordered, the default collation is sorted in order of ascending key of the dictionary.

Code TreeMap class declaration is as follows:

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
	......
}
复制代码

Use HashMap TreeMap class and essentially the same, only the modifications to the code declared at:

TreeMap<String, String> platformMap = new TreeMap<>();
TreeMap<String, String> majorPlatfromMap = new TreeMap<>();
TreeMap<String, String> otherPlatformMap = new TreeMap<>();
复制代码

5. HashMap, the difference between Hashtable, LinkedHashMap, TreeMap's (Frequently Asked Interview)

5.1 similarities

1) HashMap, Hashtable, LinkedHashMap, TreeMap implement the Map interface

2) the four are guaranteed uniqueness of Key's, which does not allow duplicate Key

5.2 difference

5.2.1 Sorting

HashMap does not guarantee the order of elements

Hashtable does not guarantee the order of elements

LinkHashMap ensure insertion FIFO order sorted i.e.

TreeMap order to ensure that the elements, support for custom collations

Empty rumor, to see the effect on the code:

HashMap<String, String> hashMap = new HashMap<>();
Hashtable<String, String> hashtable = new Hashtable<>();
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
TreeMap<String, String> treeMap = new TreeMap<>();

String[] letterArray = new String[]{"B", "A", "D", "C", "E"};
for (String letter : letterArray) {
    hashMap.put(letter, letter);
    hashtable.put(letter, letter);
    linkedHashMap.put(letter, letter);
    treeMap.put(letter, letter);
}

System.out.println("HashMap(我不保证顺序):" + hashMap);
System.out.println("Hashtable(我不保证顺序):" + hashtable);
System.out.println("LinkedHashMap(我保证元素插入时的顺序):" + linkedHashMap);
System.out.println("TreeMap(我按排序规则保证元素的顺序):" + treeMap);
复制代码

The output of the above code:

The HashMap (I do not guarantee the order): {A = A, B = B, C = C, D = D, E = E}

Hashtable (I do not guarantee the order): {A = A, E = E, D = D, C = C, B = B}

A LinkedHashMap (I guarantee the order in which elements are inserted): {B = B, A = A, D = D, C = C, E = E}

The TreeMap (I guarantee the order according to the collation elements): {A = A, B = B, C = C, D = D, E = E}

5.2.2 null value

HashMap, LinkedHashMap allows the addition of null values ​​(Key and Value are allowed), so the following code is legal:

HashMap<String, String> hashMap = new HashMap<>();
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();

hashMap.put(null, null);
linkedHashMap.put(null, null);
复制代码

TreeMap not allow Key has a null value, but allows Value has null value, so the following code is legal:

TreeMap<String, String> treeMap = new TreeMap<>();

treeMap.put("cnblogs.com", null);
复制代码

But treeMap.put(null, null);raises java.lang.NullPointerExceptionan exception:

Hashtable not allowed to add null value (Key and Value are not allowed), add a null value Throws java.lang.NullPointerExceptionan exception.

Hashtable<String, String> hashtable = new Hashtable<>();

hashtable.put("cnblogs.com", null);
hashtable.put(null, null);
复制代码

Running the above code, the error message as follows:

5.2.3 Thread Safety

HashMap, LinkedHashMap, TreeMap is not thread safe.

Hashtable is thread-safe, which is its advantages, but also lead to situations in theory, the efficiency is not high Hashtable HashMap.

So if there is no thread safety requirements, it is recommended to use HashMap.

5.2.4 Inheritance

The parent class is Hashtable Dictionary.

HashMap parent is AbstractMap.

LinkedHashMap parent is HashMap, HashMap parent is AbstractMap, so LinkedHashMap also inherited AbstractMap.

TreeMap parent is AbstractMap.

6. TreeMap two sort (frequently asked interview)

TreeMap default collation key is lexicographically ascending order.

First look at the example of type String TreeMap stored under:

TreeMap<String, String> treeMap = new TreeMap<>();

String[] letterArray = new String[]{"B", "A", "D", "C", "E"};
for (String letter : letterArray) {
    treeMap.put(letter, letter);
}

for (String key : treeMap.keySet()) {
    System.out.println("key:" + key + ",Value:" + treeMap.get(key));
}
复制代码

Output:

key:A,Value:A

key:B,Value:B

key:C,Value:C

key:D,Value:D

key:E,Value:E

If that is loaded in the TreeMap element type is our custom reference types, it is what sort of rules it?

With this question, we create a Student class as follows:

package collection;

public class Student {
    private String name;
    private int age;

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

    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;
    }
}
复制代码

Authentication code and add the following:

TreeMap<Student, Student> studentTreeMap = new TreeMap<>();

Student student1 = new Student("zhangsan", 20);
Student student2 = new Student("lisi", 22);
Student student3 = new Student("wangwu", 24);
Student student4 = new Student("zhaoliu", 26);

Student student5 = new Student("zhangsan", 22);

studentTreeMap.put(student1, student1);
studentTreeMap.put(student2, student2);
studentTreeMap.put(student3, student3);
studentTreeMap.put(student4, student4);
studentTreeMap.put(student5, student5);

for (Student student : studentTreeMap.keySet()) {
    System.out.println("name:" + student.getName() + ",age:" + student.getAge());
}
复制代码

Full of joy to see the code running under the effect of, only to find that reported the following errors:

Why is this so?

This is because we did not define any collation to the Student class, TreeMap say I do not know how to sort, or thrown pot thrown, ha ha.

How to solve it? There are two ways:

  1. Natural order
  2. Sort comparator

6.1 natural ordering

Natural ordering implementation is to allow the Student class implement the interface Comparable, and override compareTo method of this interface, which defines collation.

package collection;

public class Student implements Comparable<Student> {
    // 省略其它代码

    @Override
    public int compareTo(Student o) {
        return 0;
    }
}
复制代码

IDEA is generated by default the compareTo () method as shown above.

This method when executed add () method to add an element to determine the position of the element.

If it returns 0, on behalf of two identical elements to retain only the first element

If the return value is greater than 0, the element to be representative of this parameter is specified in the row behind the elements o

If the return value is less than 0, the element to be representative of this parameter is specified in the row in front of the elements o

So if compareTo () method without any modification, immediately prior to running validation code, you will find that only one set of elements:

name:zhangsan,age:20

The method is then modified at the compareTo () of logic:

@Override
public int compareTo(Student o) {
    // 排序规则描述如下
    // 按照姓名的长度排序,长度短的排在前面,长度长的排在后面
    // 如果姓名的长度相同,按字典顺序比较String
    // 如果姓名完全相同,按年龄排序,年龄小的排在前面,年龄大的排在后面

    int orderByNameLength = this.name.length() - o.name.length();
    int orderByName = orderByNameLength == 0 ? this.name.compareTo(o.name) : orderByNameLength;
    int orderByAge = orderByName == 0 ? this.age - o.age : orderByName;

    return orderByAge;
}
复制代码

Validation code prior to run again, the output results are as follows:

name:lisi,age:22

name:wangwu,age:24

name:zhaoliu,age:26

name:zhangsan,age:20

name:zhangsan,age:22

6.2 ordering comparator

Sorting implementation comparator is a comparator new class inherits the interface Comparator, rewriting the Compare () interface method.

Note: in this way using Student class does not implement the interface Comparable, but do not need to rewrite the method compareTo interface.

package collection;

import java.util.Comparator;

public class StudentComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        // 排序规则描述如下
        // 按照姓名的长度排序,长度短的排在前面,长度长的排在后面
        // 如果姓名的长度相同,按字典顺序比较String
        // 如果姓名完全相同,按年龄排序,年龄小的排在前面,年龄大的排在后面

        int orderByNameLength = o1.getName().length() - o2.getName().length();
        int orderByName = orderByNameLength == 0 ? o1.getName().compareTo(o2.getName()) : orderByNameLength;
        int orderByAge = orderByName == 0 ? o1.getAge() - o2.getAge() : orderByName;

        return orderByAge;
    }
}
复制代码

Then modify the code to the code declared at studentTreeSet verification:

TreeMap<Student, Student> studentTreeMap = new TreeMap<>(new StudentComparator());
复制代码

Output output and use of natural ordering of exactly the same.

7. Source and reference

Traversing the four methods of HashMap

TreeMap sorting

Java collection List, Set, and Map, etc. Detailed collection system (the most complete history)

8. Finally

Play a little advertising, welcomed the focus on micro-channel scan code number public: "Shanghai is a stranger" on a regular basis to share Java technology dry goods, so that we progress together.

Guess you like

Origin juejin.im/post/5d47ffb8f265da03a0495dc3