When asked about Map by an interviewer, Map should have eight questions

Posted by mhoward on Tue, 21 Dec 2021 21:15:16 +0100

Preface

I have read several foreign blogs about Java map in the last few days and have written very well, so I have sorted out eight issues that Java map should master, which are common problems in daily development. I hope they will help you. If there are any incorrect points, please mention them. Thank you very much.

1. How to convert a Map into a List

In daily development, we often encounter this scenario, converting a Map into a List. Map to List can be converted in three ways:

  • Convert map key to list
  • Convert map's value value value to list
  • Convert map key-value to list

The pseudocode is as follows:

// key list
List keyList = new ArrayList(map.keySet());
// value list
List valueList = new ArrayList(map.values());
// key-value list
List entryList = new ArrayList(map.entrySet());

Sample code:

public class Test {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(2, "jay");
        map.put(1, "whx");
        map.put(3, "huaxiao");
        //Convert a map's key to a list
        List<Integer> keyList = new ArrayList<>(map.keySet());
        System.out.println(keyList);
        //Convert map values to list s
        List<String> valueList = new ArrayList<>(map.values());
        System.out.println(valueList);
        hold map The key value of list
        List entryList = new ArrayList(map.entrySet());
        System.out.println(entryList);

    }
}

Run result:

[1, 2, 3]
[whx, jay, huaxiao]
[1=whx, 2=jay, 3=huaxiao]

2. How to traverse a Map

We often need to traverse a map, which can be implemented in two ways:

Traversal through entrySet+for

for(Entry entry: map.entrySet()) {
  // get key
  K key = entry.getKey();
  // get value
  V value = entry.getValue();
}

Instance code:

public class EntryMapTest {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(2, "jay");
        map.put(1, "whx");
        map.put(3, "huaxiao");

        for(Map.Entry entry: map.entrySet()) {
            // get key
            Integer key = (Integer) entry.getKey();
            // get value
            String value = (String) entry.getValue();

            System.out.println("key:"+key+",value:"+value);
        }
    }
}

Traversal through Iterator+while

Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {
  Entry entry = itr.next();
  // get key
  K key = entry.getKey();
  // get value
  V value = entry.getValue();
}

Instance code:

public class IteratorMapTest {
    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(2, "jay");
        map.put(1, "whx");
        map.put(3, "huaxiao");

        Iterator itr = map.entrySet().iterator();
        while(itr.hasNext()) {
            Map.Entry entry = (Map.Entry) itr.next();
            // get key
            Integer key = (Integer) entry.getKey();
            // get value
            String value = (String) entry.getValue();

            System.out.println("key:"+key+",value:"+value);
        }
    }
}

Run result:

key:1,value:whx
key:2,value:jay
key:3,value:huaxiao

3. How to sort by Map's keys

Sorting the keys of a Map is common in everyday development and is implemented in two main ways.

Put Map.Entry into the list, and then use Comparator to sort the list

List list = new ArrayList(map.entrySet());
Collections.sort(list, (Entry e1, Entry e2)-> {
    return e1.getKey().compareTo(e2.getKey());
});

Instance code:

public class SortKeysMapTest {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("2010", "jay");
        map.put("1999", "whx");
        map.put("3010", "huaxiao");

        List<Map.Entry<String,String>> list = new ArrayList<>(map.entrySet());
        Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {
                return e1.getKey().toString().compareTo(e2.getKey().toString());
        });

        for (Map.Entry entry : list) {
            System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());
        }

    }
}

Implement with SortedMap+TreeMap+Comparator

SortedMap sortedMap = new TreeMap(new Comparator() {
  @Override
  public int compare(K k1, K k2) {
    return k1.compareTo(k2);
  }
});
sortedMap.putAll(map);

Instance code:

public class SortKeys2MapTest {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("2010", "jay");
        map.put("1999", "whx");
        map.put("3010", "huaxiao");

        SortedMap sortedMap = new TreeMap(new Comparator<String>() {
            @Override
            public int compare(String k1, String k2) {
                return k1.compareTo(k2);
            }
        });
        sortedMap.putAll(map);

        Iterator itr = sortedMap.entrySet().iterator();
        while(itr.hasNext()) {
            Map.Entry entry = (Map.Entry) itr.next();
            // get key
            String key = (String) entry.getKey();
            // get value
            String value = (String) entry.getValue();

            System.out.println("key:"+key+",value:"+value);
        }
    }
}

Run result:

key:1999,value:whx
key:2010,value:jay
key:3010,value:huaxiao

4. How to sort the values of a Map

List list = new ArrayList(map.entrySet());
Collections.sort(list, (Entry e1, Entry e2) ->{
    return e1.getValue().compareTo(e2.getValue());
  });

Instance code:

public class SortValuesMapTest {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("2010", "jay");
        map.put("1999", "whx");
        map.put("3010", "huaxiao");

        List <Map.Entry<String,String>>list = new ArrayList<>(map.entrySet());
        Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {
                return e1.getValue().toString().compareTo(e2.getValue().toString());
            }
        );

        for (Map.Entry entry : list) {
            System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());
        }
    }
}

Run result:

key:3010,value:huaxiao
key:2010,value:jay
key:1999,value:whx

5. How to initialize a static/immutable Map

Initializing a static immutable map does not work with static final+static code alone, as follows:

public class Test1 {
    private static final Map <Integer,String>map;
    static {
        map = new HashMap<Integer, String>();
        map.put(1, "one");
        map.put(2, "two");
    }
    public static void main(String[] args) {
        map.put(3, "three");
        Iterator itr = map.entrySet().iterator();
        while(itr.hasNext()) {
            Map.Entry entry = (Map.Entry) itr.next();
            // get key
            Integer key = (Integer) entry.getKey();
            // get value
            String value = (String) entry.getValue();

            System.out.println("key:"+key+",value:"+value);
        }
    }
}

Here, map continues to add elements (3,'three') and finds that it is OK. The results are as follows:

key:1,value:one
key:2,value:two
key:3,value:three

Collections are required to truly implement a static and immutable map. UnmodifiableMap, code as follows:

public class Test2 {
    private static final Map<Integer, String> map;
    static {
        Map<Integer,String> aMap = new HashMap<>();
        aMap.put(1, "one");
        aMap.put(2, "two");
        map = Collections.unmodifiableMap(aMap);
    }

    public static void main(String[] args) {
        map.put(3, "3");
        Iterator itr = map.entrySet().iterator();
        while(itr.hasNext()) {
            Map.Entry entry = (Map.Entry) itr.next();
            // get key
            Integer key = (Integer) entry.getKey();
            // get value
            String value = (String) entry.getValue();

            System.out.println("key:"+key+",value:"+value);
        }
    }

}

You can find that it is wrong to continue adding elements to the map to achieve a truly immutable map.

6. Differences between HashMap, TreeMap, Hashtable, ConcurrentHashMap

HashMapTreeMapHashtableConcurrentHashMap
Orderlinessnoyesnono
null k-vYes-YesNo-YesNo-NoNo-No
Linear securitynonoyesyes
Time ComplexityO(1)O(log n)O(1)O(log n)
Underlying structureArray+Chain List+Red-Black Treered-black treeArray+Chain ListArray+Chain List+Red-Black Tree

7. How to create an empty map

If the map is immutable, you can create it as follows:

Map map=Collections.emptyMap();
or
Map<String,String> map=Collections.<String, String>emptyMap();
//map1.put("1", "1"); Run Error

If you want your empty map to add elements, you can create one like this

Map map = new HashMap();

8. Replication about map s

Replication of hashmap is also used in daily development. The main ones are=, clone, putAll, but they are all shallow copies, so be careful when you use them. Here are some examples:

Example 1, use = to copy a map:

public class CopyMapAssignTest {
    public static void main(String[] args) {

        Map<Integer, User> userMap = new HashMap<>();

        userMap.put(1, new User("jay", 26));
        userMap.put(2, new User("fany", 25));

        //Shallow clone
        Map<Integer, User> clonedMap = userMap;

        //Same as userMap
        System.out.println(clonedMap);

        System.out.println("\nChanges reflect in both maps \n");

        //Change a value is clonedMap
        clonedMap.get(1).setName("test");

        //Verify content of both maps
        System.out.println(userMap);
        System.out.println(clonedMap);
    }
}

Run result:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}

Changes reflect in both maps 

{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

As you can see from the running results, both map s have changed for the cloneMap modification, so = shallow copy.

Example 2, clone replication using hashmap:

public class CopyCloneMapTest {
    public static void main(String[] args) {
        HashMap<Integer, User> userMap = new HashMap<>();

        userMap.put(1, new User("jay", 26));
        userMap.put(2, new User("fany", 25));

        //Shallow clone
        HashMap<Integer, User> clonedMap = (HashMap<Integer, User>) userMap.clone();

        //Same as userMap
        System.out.println(clonedMap);

        System.out.println("\nChanges reflect in both maps \n");

        //Change a value is clonedMap
        clonedMap.get(1).setName("test");

        //Verify content of both maps
        System.out.println(userMap);
        System.out.println(clonedMap);
    }
}

Run result:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}

Changes reflect in both maps 

{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

As you can see from the running results, both map s have changed with the cloneMap modification, so the clone of hashmap is also a shallow copy.

Example 3, using the putAll operation

public class CopyPutAllMapTest {
    public static void main(String[] args) {
        HashMap<Integer, User> userMap = new HashMap<>();

        userMap.put(1, new User("jay", 26));
        userMap.put(2, new User("fany", 25));

        //Shallow clone
        HashMap<Integer, User> clonedMap = new HashMap<>();
        clonedMap.putAll(userMap);

        //Same as userMap
        System.out.println(clonedMap);

        System.out.println("\nChanges reflect in both maps \n");

        //Change a value is clonedMap
        clonedMap.get(1).setName("test");

        //Verify content of both maps
        System.out.println(userMap);
        System.out.println(clonedMap);
    }
}

Run result:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}

Changes reflect in both maps 

{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

As you can see from the running results, both map s have changed with the cloneMap modification, so putAll is still a shallow copy.

So how do you implement deep replication?

You can use serialization as an example of a deep copy by serializing HashMap for Google Gson:

public class CopyDeepMapTest {

    public static void main(String[] args) {
        HashMap<Integer, User> userMap = new HashMap<>();

        userMap.put(1, new User("jay", 26));
        userMap.put(2, new User("fany", 25));

        //Shallow clone
        Gson gson = new Gson();
        String jsonString = gson.toJson(userMap);

        Type type = new TypeToken<HashMap<Integer, User>>(){}.getType();
        HashMap<Integer, User> clonedMap = gson.fromJson(jsonString, type);

        //Same as userMap
        System.out.println(clonedMap);

        System.out.println("\nChanges DO NOT reflect in other map \n");

        //Change a value is clonedMap
        clonedMap.get(1).setName("test");

        //Verify content of both maps
        System.out.println(userMap);
        System.out.println(clonedMap);
    }
}

Run result:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}

Changes DO NOT reflect in other map 

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

As you can see from the running results, the userMap is not changed for the cloneMap modification, so it is a deep copy.

Reference and thanks

Topics: Java Scala