有關於Java Map,應該掌握的8個問題

前言

最近幾天看了幾篇有關於Java Map的外國博文,寫得很是不錯,因此整理了Java map 應該掌握的8個問題,都是平常開發司空見慣的問題,但願對你們有幫助;若是有不正確的地方,歡迎提出,萬分感謝哈~java

本章節全部代碼demo已上傳githubgit

一、如何把一個Map轉化爲List

平常開發中,咱們常常遇到這種場景,把一個Map轉化爲List。map轉List有如下三種轉化方式:github

  • 把map的鍵key轉化爲list
  • 把map的值value轉化爲list
  • 把map的鍵值key-value轉化爲list

僞代碼以下:json

// 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());
複製代碼

示例代碼:數組

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");
        //把一個map的鍵轉化爲list
        List<Integer> keyList = new ArrayList<>(map.keySet());
        System.out.println(keyList);
        //把map的值轉化爲list
        List<String> valueList = new ArrayList<>(map.values());
        System.out.println(valueList);
        把map的鍵值轉化爲list
        List entryList = new ArrayList(map.entrySet());
        System.out.println(entryList);

    }
}
複製代碼

運行結果:安全

[1, 2, 3]
[whx, jay, huaxiao]
[1=whx, 2=jay, 3=huaxiao]
複製代碼

二、如何遍歷一個Map

咱們常常須要遍歷一個map,能夠有如下兩種方式實現:bash

經過entrySet+for實現遍歷

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

實例代碼:ide

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);
        }
    }
}
複製代碼

經過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();
}
複製代碼

實例代碼:學習

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);
        }
    }
}
複製代碼

運行結果:ui

key:1,value:whx
key:2,value:jay
key:3,value:huaxiao
複製代碼

三、如何根據Map的keys進行排序

對Map的keys進行排序,在平常開發很常見,主要有如下兩種方式實現。

把Map.Entry放進list,再用Comparator對list進行排序

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

實例代碼:

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());
        }

    }
}
複製代碼

使用SortedMap+TreeMap+Comparator實現

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

實例代碼:

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);
        }
    }
}

複製代碼

運行結果:

key:1999,value:whx
key:2010,value:jay
key:3010,value:huaxiao
複製代碼

四、如何對Map的values進行排序

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

實例代碼:

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());
        }
    }
}
複製代碼

運行結果:

key:3010,value:huaxiao
key:2010,value:jay
key:1999,value:whx
複製代碼

五、如何初始化一個靜態/不可變的Map

初始化一個靜態不可變的map,單單static final+static代碼仍是不行的,以下:

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);
        }
    }
}
複製代碼

這裏面,map繼續添加元素(3,"three"),發現是OK的,運行結果以下:

key:1,value:one
key:2,value:two
key:3,value:three
複製代碼

真正實現一個靜態不可變的map,須要Collections.unmodifiableMap,代碼以下:

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);
        }
    }

}
複製代碼

運行結果以下:

能夠發現,繼續往map添加元素是會報錯的,實現真正不可變的map。

六、HashMap, TreeMap, and Hashtable,ConcurrentHashMap的區別

HashMap TreeMap Hashtable ConcurrentHashMap
有序性
null k-v 是-是 否-是 否-否 否-否
線性安全
時間複雜度 O(1) O(log n) O(1) O(log n)
底層結構 數組+鏈表 紅黑樹 數組+鏈表 紅黑樹

七、如何建立一個空map

若是map是不可變的,能夠這樣建立:

Map map=Collections.emptyMap();
or
Map<String,String> map=Collections.<String, String>emptyMap();
//map1.put("1", "1"); 運行出錯
複製代碼

若是你但願你的空map能夠添加元素的,能夠這樣建立

Map map = new HashMap();
複製代碼

八、有關於map的複製

有關於hashmap的複製,在平常開發中,使用也比較多。主要有=,clone,putAll,可是他們都是淺複製,使用的時候注意啦,能夠看一下如下例子:

例子一,使用=複製一個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);
    }
}
複製代碼

運行結果:

{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}}
複製代碼

從運行結果看出,對cloneMap修改,兩個map都改變了,因此=是淺複製。

例子二,使用hashmap的clone複製:

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);
    }
}

複製代碼

運行結果:

{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}}
複製代碼

從運行結果看出,對cloneMap修改,兩個map都改變了,因此hashmap的clone也是淺複製。

例子三,經過putAll操做

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);
    }
}

複製代碼

運行結果:

{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}}
複製代碼

從運行結果看出,對cloneMap修改,兩個map都改變了,因此putAll仍是淺複製。

那麼,如何實現深度複製呢?

可使用序列化實現,以下爲谷歌Gson序列化HashMap,實現深度複製的例子:

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);
    }
}

複製代碼

運行結果:

{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}}
複製代碼

從運行結果看出,對cloneMap修改,userMap沒有被改變,因此是深度複製。

參考與感謝

我的公衆號

  • 若是你是個愛學習的好孩子,能夠關注我公衆號,一塊兒學習討論。
  • 若是你以爲本文有哪些不正確的地方,能夠評論,也能夠關注我公衆號,私聊我,你們一塊兒學習進步哈。
相關文章
相關標籤/搜索