Java 8 – How to sort a Map
Java 8 Stream
examples to sort a Map
, by keys or by values.
1. Quick Explanation
Steps to sort a Map in Java 8.
- Convert a Map into a Stream
- Sort it
- 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.
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.
Not using Java 8? Try this classic way to sort a Map in Java.
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 ?
If the key is duplicated, do you prefer oldKey or newKey?
See this example – https://www.mkyong.com/java8/java-8-convert-list-to-map/
there is no way map should have duplicate key then why we are using (old value, new value)-> old value
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
I think you should change the variables names, “oldValue” and “newValue” is really confusing.
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.
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 🙂
Really nice example programs, I love this site
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
Article is updated, thanks for your inputs.
I get different error, but on java 17 it’s not working for me.
not enough explanation.
Thanks! Very Helpfull!
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));
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;
}
How can i sort according to UTF-8 in this way ?
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.
How to handle null key/value here?
stream.filter, review the following example :
https://www.mkyong.com/java8/java-8-filter-a-null-value-from-a-stream/
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
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 🙂
Thanks, very clear.
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.
Please expline deeply
The source code should be self-explanatory, which lines need to explain more?