Java doesn't have a direct API to sort a HashMap or LinkedHashMap. However, you can try using the following ways
Sort by key objects via converting HashMap and LinkedHashMap collection to TreeMap
Sort by key and by value objects via converting entrySet() of HashMap and LinkedHashMap to TreeSet or ArrayList
Apart from that, Comparable and Comparator have to be used to define the sort key and control the sort order
Let's walk through this tutorial to explore in more details
Sort by keys via TreeMap
You can sort a HashMap and LinkedHashMap by keys via TreeMap with the below steps
Converting a HashMap or LinkedHashMap collection to TreeMap via TreeMap constructor
Use Comparable or Comparator to extract the sort field and control over the sorting order of the keys depending on which TreeMap constructor is used at the creation time
Then you get the TreeMap in sorted order
The following gives you some specific examples in practice
If you use TreeMap<>(Map) constructor to convert, the sorting logic will be based on the Comparable natural ordering of the key objects
In the below example, Comparable is implemented in String by default. The
descendingMap()
method of a TreeMap instance can also be used to get the reversed order from the default Comparable implementation
@Test
public void sortByKeys_WithTreeMapAndComparable() {
Map.Entry<String, Integer> e1 = Map.entry("k1", 1);
Map.Entry<String, Integer> e2 = Map.entry("k2", 2);
Map.Entry<String, Integer> e3 = Map.entry("k3", 3);
Map<String, Integer> map = new HashMap<>(Map.ofEntries(e3, e1, e2));
NavigableMap<String, Integer> treeMap1 = new TreeMap<>(map);
assertThat(treeMap1).containsExactly(e1, e2, e3);
NavigableMap<String, Integer> treeMap2 = treeMap1.descendingMap();
assertThat(treeMap2).containsExactly(e3, e2, e1);
}
If you use TreeMap<>(Comparator) constructor in conjunction with putAll(Map) method to convert, the sorting logic will be controlled by the given Comparator
The ordering can be inherited from the implemented Comparable of the underlying key objects with Comparator.naturalOrder() or in the reverse order with Comparator.reverseOrder()
@Test
public void sortByKeys_WithTreeMapAndComparator() {
Map.Entry<String, Integer> e1 = Map.entry("k1", 1);
Map.Entry<String, Integer> e2 = Map.entry("k02", 2);
Map.Entry<String, Integer> e3 = Map.entry("k3", 3);
Map<String, Integer> map = new HashMap<>(Map.ofEntries(e3, e1, e2));
NavigableMap<String, Integer> treeMap1 = new TreeMap<>(Comparator.reverseOrder());
treeMap1.putAll(map);
assertThat(treeMap1).containsExactly(e3, e1, e2);
NavigableMap<String, Integer> treeMap2 = treeMap1.descendingMap();
assertThat(treeMap2).containsExactly(e2, e1, e3);
}
- A custom sorting logic can be specified to the
TreeMap<>(Comparator)
constructor withComparator.comparing(keyExtractor, keyComparator)
in whichkeyExtractor
is a function to extract the sort key from the underlying key objects andkeyComparator
is used to compare the sort key
@Test
public void sortByKeys_WithTreeMapAndCustomComparator() {
Category c1 = new Category(1, "c1");
Category c2 = new Category(20, "c2");
Category c3 = new Category(3, "c2");
Book b1 = new Book(1, "b1");
Book b2 = new Book(20, "b2");
Book b3 = new Book(3, "b2");
Map.Entry<Category, Book> cb1 = Map.entry(c1, b1);
Map.Entry<Category, Book> cb2 = Map.entry(c2, b2);
Map.Entry<Category, Book> cb3 = Map.entry(c3, b3);
Map<Category, Book> map = new HashMap<>(Map.ofEntries(cb3, cb1, cb2));
Comparator<Category> c = Comparator
.comparing(Category::getName, Comparator.reverseOrder())
.thenComparing(Category::getId, Comparator.reverseOrder());
NavigableMap<Category, Book> treeMap1 = new TreeMap<>(c);
treeMap1.putAll(map);
assertThat(treeMap1).containsExactly(cb2, cb3, cb1);
NavigableMap<Category, Book> treeMap2 = treeMap1.descendingMap();
assertThat(treeMap2).containsExactly(cb1, cb3, cb2);
}
static class Category {
int id;
String name;
Category(int id, String name) {
this.id = id;
this.name = name;
}
int getId() { return id;}
String getName() { return name;}
}
static class Book {
int id;
String title;
Book(int id, String title) {
this.id = id;
this.title = title;
}
int getId() {
return id;
}
String getTitle() {
return title;
}
}
Sort by keys and by values via TreeSet
The following steps can be used to sort a HashMap and LinkedHashMap by keys and by values via TreeSet
Provide either comparingByKey(), comparingByKey(Comparator), comparingByValue() or comparingByValue(Comparator) static methods of Map.Entry to TreeSet(Comparator) constructor to create a new TreeSet
Use
addAll(Collection)
method of the created TreeSet to import entrySet() from the HashMap and LinkedHashMap you 'd like to sortNow you get a TreeSet of
Map.Entry
in sorted order
The below gives you specific use case examples in practice
- If you use
comparingByKey()
andcomparingByValue()
, the Comparable natural order of the underlying key and value objects will be applied as the sorting logic. In the following example, String and Integer are implemented Comparable by default
@Test
public void sortByKeysAndByValues_WithTreeSetAndComparable() {
Map.Entry<String, Integer> e1 = Map.entry("k1", 1);
Map.Entry<String, Integer> e2 = Map.entry("k2", 20);
Map.Entry<String, Integer> e3 = Map.entry("k3", 3);
Map<String, Integer> map = new HashMap<>(Map.ofEntries(e3, e1, e2));
NavigableSet<Map.Entry<String, Integer>> treeSet1 = new TreeSet<>(comparingByKey());
treeSet1.addAll(map.entrySet());
assertThat(treeSet1).containsExactly(e1, e2, e3);
NavigableSet<Map.Entry<String, Integer>> treeSet2 = new TreeSet<>(comparingByValue());
treeSet2.addAll(map.entrySet());
assertThat(treeSet2).containsExactly(e1, e3, e2);
}
If you use
comparingByKey(Comparator)
andcomparingByValue(Comparator)
, the sorting logic will be defined by the given ComparatorThe ordering can be inherited from the implemented Comparable of the underlying key or value objects with Comparator.naturalOrder() or in the reverse order with Comparator.reverseOrder()
comparingByKey(Comparator.naturalOrder()) and comparingByValue(Comparator.naturalOrder()) have the same effect as comparingByKey() and comparingByValue()
@Test
public void sortByKeysAndByValues_WithTreeSetAndComparator() {
Map.Entry<String, Integer> e1 = Map.entry("k1", 1);
Map.Entry<String, Integer> e2 = Map.entry("k2", 20);
Map.Entry<String, Integer> e3 = Map.entry("k3", 3);
Map<String, Integer> map = new HashMap<>(Map.ofEntries(e3, e1, e2));
NavigableSet<Map.Entry<String, Integer>> treeSet1 = new TreeSet<>(comparingByKey(Comparator.reverseOrder()));
treeSet1.addAll(map.entrySet());
assertThat(treeSet1).containsExactly(e3, e2, e1);
NavigableSet<Map.Entry<String, Integer>> treeSet2 = new TreeSet<>(comparingByValue(Comparator.reverseOrder()));
treeSet2.addAll(map.entrySet());
assertThat(treeSet2).containsExactly(e2, e3, e1);
}
- A custom Comparator sorting logic can be specified to the
comparingByKey(Comparator)
andcomparingByValue(Comparator)
withComparator.comparing(keyExtractor, keyComparator)
in whichkeyExtractor
is a function to extract the sort key from the underlying key or value objects andkeyComparator
is used to compare the sort key
@Test
public void sortByKeysAndByValues_WithTreeSetAndCustomComparator() {
Category c1 = new Category(1, "c1");
Category c2 = new Category(20, "c2");
Category c3 = new Category(3, "c2");
Book b1 = new Book(1, "b1");
Book b2 = new Book(20, "b2");
Book b3 = new Book(3, "b2");
Map.Entry<Category, Book> cb1 = Map.entry(c1, b1);
Map.Entry<Category, Book> cb2 = Map.entry(c2, b2);
Map.Entry<Category, Book> cb3 = Map.entry(c3, b3);
Map<Category, Book> map = new HashMap<>(Map.ofEntries(cb3, cb1, cb2));
Comparator<Category> categoryComparator = Comparator
.comparing(Category::getName, Comparator.reverseOrder())
.thenComparing(Category::getId, Comparator.reverseOrder());
NavigableSet<Map.Entry<Category, Book>> treeSet1 = new TreeSet<>(comparingByKey(categoryComparator));
treeSet1.addAll(map.entrySet());
assertThat(treeSet1).containsExactly(cb2, cb3, cb1);
Comparator<Book> bookComparator = Comparator
.comparing(Book::getTitle, Comparator.reverseOrder())
.thenComparing(Book::getId, Comparator.reverseOrder());
NavigableSet<Map.Entry<Category, Book>> treeSet2 = new TreeSet<>(comparingByValue(bookComparator));
treeSet2.addAll(map.entrySet());
assertThat(treeSet2).containsExactly(cb2, cb3, cb1);
}
You can find the definition of Category and Book in the previous or conclusion section
Sort by keys and by values via ArrayList
The following steps can be used to sort a HashMap and LinkedHashMap by keys and by values via ArrayList
Provide entrySet() of the HashMap and LinkedHashMap you'd like sorting to the ArrayList(Collection) constructor to create and initialize a new ArrayList
Provide either comparingByKey(), comparingByKey(Comparator), comparingByValue() or comparingByValue(Comparator) static methods of Map.Entry to the sort(Comparator) method of the created ArrayList
Then you get an ArrayList of
Map.Entry
elements in sorted order
The below gives you specific use case examples in practice
As noted in the previous section, you can use comparingByKey(), comparingByKey(Comparator.naturalOrder()), comparingByValue(), comparingByValue(Comparator.naturalOrder()) to inherit the sorting logic defined by the Comparable of the underlying key and value objects
comparingByKey(Comparator.reverseOrder()) and comparingByValue(Comparator.reverseOrder()) can also be used to reverse the ordering defined by Comparable
@Test
public void sortByKeysAndByValues_WithArrayListAndComparator() {
Map.Entry<String, Integer> e1 = Map.entry("k1", 1);
Map.Entry<String, Integer> e2 = Map.entry("k2", 20);
Map.Entry<String, Integer> e3 = Map.entry("k3", 3);
Map<String, Integer> map = new HashMap<>(Map.ofEntries(e3, e1, e2));
List<Map.Entry<String, Integer>> arrayList1 = new ArrayList<>(map.entrySet());
arrayList1.sort(comparingByKey(Comparator.naturalOrder()));
assertThat(arrayList1).containsExactly(e1, e2, e3);
List<Map.Entry<String, Integer>> arrayList2 = new ArrayList<>(map.entrySet());
arrayList2.sort(comparingByValue(Comparator.reverseOrder()));
assertThat(arrayList2).containsExactly(e2, e3, e1);
}
- A custom Comparator sorting logic can be specified to the comparingByKey(Comparator) and comparingByValue(Comparator) with
Comparator.comparing(keyExtractor, keyComparator)
in whichkeyExtractor
is a function to extract the sort key from the underlying key or value objects andkeyComparator
is used to compare the sort key
@Test
public void sortByKeysAndByValues_WithArrayListAndCustomComparator() {
Category c1 = new Category(1, "c1");
Category c2 = new Category(20, "c2");
Category c3 = new Category(3, "c2");
Book b1 = new Book(1, "b1");
Book b2 = new Book(20, "b2");
Book b3 = new Book(3, "b2");
Map.Entry<Category, Book> cb1 = Map.entry(c1, b1);
Map.Entry<Category, Book> cb2 = Map.entry(c2, b2);
Map.Entry<Category, Book> cb3 = Map.entry(c3, b3);
Map<Category, Book> map = new HashMap<>(Map.ofEntries(cb3, cb1, cb2));
Comparator<Category> categoryComparator = Comparator
.comparing(Category::getName, Comparator.reverseOrder())
.thenComparing(Category::getId, Comparator.reverseOrder());
List<Map.Entry<Category, Book>> arrayList1 = new ArrayList<>(map.entrySet());
arrayList1.sort(comparingByKey(categoryComparator));
assertThat(arrayList1).containsExactly(cb2, cb3, cb1);
Comparator<Book> bookComparator = Comparator
.comparing(Book::getTitle, Comparator.reverseOrder())
.thenComparing(Book::getId, Comparator.reverseOrder());
List<Map.Entry<Category, Book>> arrayList2 = new ArrayList<>(map.entrySet());
arrayList2.sort(comparingByValue(bookComparator));
assertThat(arrayList2).containsExactly(cb2, cb3, cb1);
}
You can find the definition of Category and Book in the conclusion section
Learn more about sorting in ArrayList
Comparable and Comparator
In short, Comparable
and Comparator
provide the default and custom sorting logic, respectively, to the underlying objects in an array or collection
Learn more about Comparable and Comparator
Conclusion
In this tutorial, we learned to sort a HashMap or LinkedHashMap by keys or by values via converting it to TreeMap, TreeSet or ArrayList. You can find below the full source code