Java 8 – How to sort a Map

sorting

Java 8 Stream examples to sort a Map, by keys or by values.

1. Quick Explanation

Steps to sort a Map in Java 8.

  1. Convert a Map into a Stream
  2. Sort it
  3. Collect and return a new LinkedHashMap (keep the order)

Map result = map.entrySet().stream()
	.sorted(Map.Entry.comparingByKey()) 			
	.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
	(oldValue, newValue) -> oldValue, LinkedHashMap::new));

P.S By default, Collectors.toMap will returns a HashMap

2. Sort by Keys

SortByKeyExample.java

package com.mkyong.test;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class SortByKeyExample {

    public static void main(String[] argv) {

        Map<String, Integer> unsortMap = new HashMap<>();
        unsortMap.put("z", 10);
        unsortMap.put("b", 5);
        unsortMap.put("a", 6);
        unsortMap.put("c", 20);
        unsortMap.put("d", 1);
        unsortMap.put("e", 7);
        unsortMap.put("y", 8);
        unsortMap.put("n", 99);
        unsortMap.put("g", 50);
        unsortMap.put("m", 2);
        unsortMap.put("f", 9);

        System.out.println("Original...");
        System.out.println(unsortMap);

        // sort by keys, a,b,c..., and return a new LinkedHashMap
        // toMap() will returns HashMap by default, we need LinkedHashMap to keep the order.
        Map<String, Integer> result = unsortMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));


        // Not Recommend, but it works.
        //Alternative way to sort a Map by keys, and put it into the "result" map
        Map<String, Integer> result2 = new LinkedHashMap<>();
        unsortMap.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .forEachOrdered(x -> result2.put(x.getKey(), x.getValue()));

        System.out.println("Sorted...");
        System.out.println(result);
        System.out.println(result2);

    }

}

Output


Original...
{a=6, b=5, c=20, d=1, e=7, f=9, g=50, y=8, z=10, m=2, n=99}

Sorted...
{a=6, b=5, c=20, d=1, e=7, f=9, g=50, m=2, n=99, y=8, z=10}
{a=6, b=5, c=20, d=1, e=7, f=9, g=50, m=2, n=99, y=8, z=10}

3. Sort by Values

SortByValueExample.java

package com.mkyong.test;

package com.mkyong;

import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class SortByValueExample {

    public static void main(String[] argv) {

        Map<String, Integer> unsortMap = new HashMap<>();
        unsortMap.put("z", 10);
        unsortMap.put("b", 5);
        unsortMap.put("a", 6);
        unsortMap.put("c", 20);
        unsortMap.put("d", 1);
        unsortMap.put("e", 7);
        unsortMap.put("y", 8);
        unsortMap.put("n", 99);
        unsortMap.put("g", 50);
        unsortMap.put("m", 2);
        unsortMap.put("f", 9);

        System.out.println("Original...");
        System.out.println(unsortMap);

        //sort by values, and reserve it, 10,9,8,7,6...
        Map<String, Integer> result = unsortMap.entrySet().stream()
                .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

						
        //Alternative way
        Map<String, Integer> result2 = new LinkedHashMap<>();
        unsortMap.entrySet().stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
                .forEachOrdered(x -> result2.put(x.getKey(), x.getValue()));

        System.out.println("Sorted...");
        System.out.println(result);
        System.out.println(result2);

    }
}

Output


Original...
{a=6, b=5, c=20, d=1, e=7, f=9, g=50, y=8, z=10, m=2, n=99}

Sorted...
{n=99, g=50, c=20, z=10, f=9, y=8, e=7, a=6, b=5, m=2, d=1}
{n=99, g=50, c=20, z=10, f=9, y=8, e=7, a=6, b=5, m=2, d=1}

4. Map<Object,Object>

The Stream can’t sort the Map<Object,Object> directly. To solve it, convert it into Map<String,String>, review below example.

Note
If you have better idea to sort it, do let me know.
DisplayApp.java

package com.mkyong;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;

public class DisplayApp {

    public static void main(String[] args) {

        Properties properties = System.getProperties();
        // not easy to sort this
        Set<Map.Entry<Object, Object>> entries = properties.entrySet();

        LinkedHashMap<String, String> collect = entries.stream()
                //Map<String, String>
                .collect(Collectors.toMap(k -> (String) k.getKey(), e -> (String) e.getValue()))
                .entrySet()
                .stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));

        collect.forEach((k, v) -> System.out.println(k + ":" + v));

    }

}
Note
Not using Java 8? Try this classic way to sort a Map in Java.

References

  1. How to sort a Map in Java
  2. LinkedHashMap JavaDoc
  3. Collectors.toMap() JavaDoc
  4. More Fun with Wildcards
  5. Collections.sort() signature
  6. Difference between and in Java

26 comments on “Java 8 – How to sort a Map

  1. HashMap<Integer,String> hm=new HashMap();
    
    hm.put(3,"INDIA");
    hm.put(1, "JAPAN");
    hm.put(2,"CHINA");
    System.out.println(hm);
    
    
       List<String> st= hm.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.
               toMap(Map.Entry::getKey,Map.Entry::getValue,(oldValue,newValue)->oldValue,LinkedHashMap::new));
    
    In the Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue, --- I get compilation error saying that Non-static method cannot be referenced from a static context .
     
    are you not getting same compilation issue ? I am using Java 16 version .
    
    
    Reply
    1. I get different error, but on java 17 it’s not working for me.

      Reply
  2. Properties properties = System.getProperties();
    // not easy to sort this
    Set entries = properties.entrySet();

    LinkedHashMap collect = entries
    .stream()
    .sorted(Map.Entry.comparingByKey(Comparator.comparing(Object::toString)))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
    (oldValue, newValue) -> oldValue, LinkedHashMap::new));

    Reply
  3. for custom objects, I was using below method and seems like it is working fine:

    Foe e.g. Student class:

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

    public int getId() {
    return id;
    }
    public void setId(int id) {
    this.id = id;
    }
    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;
    }
    }

    Sort by student id:

    public Map getSortedMapCustomAsc(Map map){
    LinkedHashMap collect = map.entrySet().stream()
    .sorted(Map.Entry.comparingByValue((Comparator)(o1,o2)->{if(o1.getId()>o2.getId()) return 1;return 0;}))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
    (oldValue, newValue) -> oldValue, LinkedHashMap::new));
    return collect;
    }

    Reply
  4. Reg : The Stream can’t sort the Map directly. To solve it, convert it into Map
    for workaround use below line whenever you need sorting on map.
    –> Map sortedMymap = new TreeMap((Comparator)(o1,o2)->{if(o1.getId()>o2.getId()) return -1;return 0;});

    Note : it is completely key based.

    I hope it helps 🙂

    Reply
  5. Hi mkyong,
    just need small help in my scenario like
    map(user0,value
    user1,value
    user2,value
    passo,value
    pass1,value
    pass2,value
    url0,value
    url1,value
    url2,value)

    I want the output as
    map(user0,value
    pass0,value
    url0,value
    user1,value
    pass1,value
    url1,value
    …..)
    like this could you please help me with the logic.
    I used tree map already which is not working as expected.

    Reply
      1. Hi Mkyong, i had a scenario where values of map is null and it is failing (oldvalue, newvalue) -> oldvalue, LinkedHashMap::new) logic. I can’t filter out the null values they are part of my final object and i am doing sorting based on Map key. can you please suggest

        Reply
        1. instead use nullsFirst() or nullsLast()
          map.entrySet().stream().sorted(Map.Entry.comparingByKeys(Comparator.nullsFirst(Comparator.naturalOrder()))).collect(Entry::getKey, Entry:: getValue, (x, y) -> x, LinkedHashMap::new)

          Hope this helps 🙂

          Reply
  6. Map result = unsortMap.entrySet().stream()
    .sorted(Map.Entry.comparingByKey())
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
    (oldValue, newValue) -> oldValue, LinkedHashMap::new));

    I am sorry but what does it mean (oldValue, newValue) -> oldValue ?

    Reply
    1. Map result = unsortMap.entrySet().stream()
      .sorted(Map.Entry.comparingByKey())
      .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
      won’t cause any compile problems, but the keys might be duplicate, in which case throw
      “java.lang.IllegalStateException: Duplicate key” exception.
      by using extra arguments “(oldValue, newValue) -> oldValue, LinkedHashMap::new”
      method will be overloaded as “R collect(Collector collector);”
      this will make sure mergeFunction (oldValue, newValue) -> oldValue be passed in, and duplicate keys removed.

      Reply
      1. I think you should change the variables names, “oldValue” and “newValue” is really confusing.

        Reply
      2. there is no way map should have duplicate key then why we are using (old value, new value)-> old value

        Reply
        1. In this scenario, it is not much needed. However, M
          kyong wanted to showcase all the available features of Collectors.toMap in an example. It would be useful when we use comparingByValue

          Reply
  7. Hi Mkyong,

    Please note that is not recommended to use foreach to populate other collection. The collect operation is more preferable in this case.

    unsortedMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue())
    .collect(toMap(Map.Entry::getKey, Map.Entry::getValue,
    (e1,e2) -> e1, LinkedHashMap::new));

    instead of

    //sort by key, a,b,c…, and put it into the “result” map
    unsortMap.entrySet().stream()
    .sorted(Map.Entry.comparingByKey())
    .forEachOrdered(x -> result.put(x.getKey(), x.getValue()));

    Best Regards,
    Anton

    Reply
  8. Wow this is very powerful! Can you comment on the time complexity required to do such an operation? Your code is pretty self-explanatory but I am unsure about the underlying mechanisms Java is using to do the sorting.

    Reply
    1. The source code should be self-explanatory, which lines need to explain more?

      Reply

Leave a Comment

Your email address will not be published. Required fields are marked *