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 with Comparator.comparing(keyExtractor, keyComparator) in which keyExtractor is a function to extract the sort key from the underlying key objects and keyComparator 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 sort

  • Now you get a TreeSet of Map.Entry in sorted order

The below gives you specific use case examples in practice

  • If you use comparingByKey() and comparingByValue(), 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) and comparingByValue(Comparator), the sorting logic will be defined by the given Comparator

    The 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) and comparingByValue(Comparator) with Comparator.comparing(keyExtractor, keyComparator) in which keyExtractor is a function to extract the sort key from the underlying key or value objects and keyComparator 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 which keyExtractor is a function to extract the sort key from the underlying key or value objects and keyComparator 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


Share to social

Van N.

Van N. is a software engineer, creator of HelloKoding. He loves coding, blogging, and traveling. You may find him on GitHub and LinkedIn