I just announced the new Spring Boot 2 material, coming in REST With Spring:

>> CHECK OUT THE COURSE

1. Introduction

In this quick tutorial, we’ll learn how to sort a HashMap in Java.

More specifically, we’ll look at sorting HashMap entries by their key or value using:

  • TreeMap
  • ArrayList and Collections.sort()
  • TreeSet
  • Using the Stream API, and finally,
  • Using the Guava library

2. Using a TreeMap

As we know, keys in TreeMap are sorted using their natural order. This is a good solution when we want to sort the key-value pairs by their key. So the idea is to push all the data from our HashMap into the TreeMap.

For starters, let’s define a HashMap and initialize it with some data:

Map<String, Employee> map = new HashMap<>();

Employee employee1 = new Employee(1L, "Mher");
map.put(employee1.getName(), employee1);
Employee employee2 = new Employee(22L, "Annie");
map.put(employee2.getName(), employee2);
Employee employee3 = new Employee(8L, "John");
map.put(employee3.getName(), employee3);
Employee employee4 = new Employee(2L, "George");
map.put(employee4.getName(), employee4);

For the Employee class, note that we’ve implemented Comparable:

public class Employee implements Comparable<Employee> {

    private Long id;
    private String name;

    // constructor, getters, setters

    // override equals and hashCode
    @Override
    public int compareTo(Employee employee) {
        return (int)(this.id - employee.getId());
    }
}

Next, we store the entries in the TreeMap by using its constructor:

TreeMap<String, Employee> sorted = new TreeMap<>(map);

Or, the putAll method to copy the data:

TreeMap<String, Employee> sorted = new TreeMap<>();
sorted.putAll(map);

And that’s it! To make sure our map entries are sorted by key, let’s print them out:

Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}

As we see, the keys are sorted in natural order.

3. Using ArrayList

Of course, we can sort the entries of the map with the help of ArrayList. The key difference from the previous method is that we don’t maintain the Map interface here.

3.1. Sort by Key

Let’s load the key set into an ArrayList:

List<String> employeeByKey = new ArrayList<>(map.keySet());
Collections.sort(employeeByKey);

And the output is:

[Annie, George, John, Mher]

3.2. Sort by Value

Now, what if we want to sort our map values by the id field of Employee object? We can use an ArrayList for that, too.

First, let’s copy the values into the list:

List<Employee> employeeById = new ArrayList<>(map.values());

And after that, we sort it:

Collections.sort(employeeById);

Remember that this works because Employee implements the Comparable interface. Otherwise, we’d need to define a manual comparator for our call to Collections.sort.

To check the results, we print the employeeById:

[Employee{id=1, name='Mher'}, 
Employee{id=2, name='George'}, 
Employee{id=8, name='John'}, 
Employee{id=22, name='Annie'}]

As we see, the objects are sorted by their id field.

4. Using a TreeSet 

In case we don’t want to accept duplicate values in our sorted collection, there is a nice solution with TreeSet.

First, let’s add some duplicate entries to our initial map:

Employee employee5 = new Employee(1L, "Mher");
map.put(employee5.getName(), employee5);
Employee employee6 = new Employee(22L, "Annie");
map.put(employee6.getName(), employee6);

4.1. Sort by Key

To sort the map by its key entries:

SortedSet<String> keySet = new TreeSet<>(map.keySet());

Let’s print the keySet and see the output:

[Annie, George, John, Mher]

Now we have the map keys sorted without the duplicates.

4.2. Sort by Value

Likewise, for the map values, the conversion code looks like:

SortedSet<Employee> values = new TreeSet<>(map.values());

And the results are:

[Employee{id=1, name='Mher'}, 
Employee{id=2, name='George'}, 
Employee{id=8, name='John'}, 
Employee{id=22, name='Annie'}]

As we can see, there are no duplicates in the output. This works with custom objects when we override equals and hashCode.

5. Using Lambdas And Streams

Since the Java 8, we can use the Stream API and lambda expressions to sort the map. All we need is to call the sorted method over the map’s stream pipeline.

5.1. Sort by Key

To sort by key, we use the comparingByKey comparator:

map.entrySet()
  .stream()
  .sorted(Map.Entry.<String, Employee>comparingByKey())
  .forEach(System.out::println);

The final forEach stage prints out the results:

Annie=Employee{id=22, name='Annie'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Mher=Employee{id=1, name='Mher'}

By default, the sorting mode is ascending.

5.2. Sort by Value

Of course, we can sort by the Employee objects as well:

map.entrySet()
  .stream()
  .sorted(Map.Entry.comparingByValue())
  .forEach(System.out::println);

As we see, the code above prints out a map sorted by the id fields of Employee objects:

Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}

Additionally, we can collect the results into a new map:

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

Note that we collected our results into a LinkedHashMap. By default, Collectors.toMap returns a new HashMap, but as we know, HashMap doesn’t guarantee iteration order, while LinkedHashMap does.

6. Using Guava

Lastly, a library that allows us to sort the HashMap is Guava. Before we start, it’ll be useful to check our write-up about maps in Guava.

First, let’s declare an Ordering as we want to sort our map by Employee’s Id field:

Ordering naturalOrdering = Ordering.natural()
  .onResultOf(Functions.forMap(map, null));

Now, all we need is to use ImmutableSortedMap to illustrate the results:

ImmutableSortedMap.copyOf(map, naturalOrdering);

And once again, the output is a map ordered by the id field:

Mher=Employee{id=1, name='Mher'}
George=Employee{id=2, name='George'}
John=Employee{id=8, name='John'}
Annie=Employee{id=22, name='Annie'}

7. Summary

In this article, we reviewed a number of ways to sort a HashMap by key or by value.

And we took a close look at how we can do this when the attribute is a custom class by implementing Comparable.

Finally, as always, the code used during the discussion can be found over on GitHub.

I just announced the new Spring Boot 2 material, coming in REST With Spring:

>> CHECK OUT THE LESSONS

3
Leave a Reply

avatar
1 Comment threads
2 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
2 Comment authors
Loredana CrusoveanuPetar Tseperski Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Petar Tseperski
Guest
Petar Tseperski

Hello @Eugen, I notice that in the example with the TreeMap, the collection is sorted by values (lexicographical order of names) instead of by id, like how you implemented the compareTo() method:

@Override
public int compareTo(Employee employee) {
return (int)(this.id – employee.getId());
}

And by the way, why do you subtract the ids?

Petar Tseperski
Guest
Petar Tseperski

Oh, my bad… I just saw, that the names are actually the key and the ids are the values, not vice versa

Loredana Crusoveanu
Editor

Hey Petar,

Yes, the keys are String names, and the values are actually Employee objects. The Employee class compareTo() method compares 2 Employee objects by id – the result of subtracting two int values shows which one is larger. For example, 8 – 5 = 3, which is a positive integer – which means 8 is greater than 5.

Hope that makes sense.