How to sort a Map in java 8 / Sort a map using Stream

Sorting values means arranging them in a particular order. The order may be ascending or descending. When the term sorting refers to a Map, it may be sorted on the basis of its keys or values. It depends completely on the requirement.

Java 8 provides a convenient method to sort a map. Using this method will cut down the lines of code used by traditional methods of using java.util.TreeMapor java.util.Comparator to some extent.

Sorting By Keys

When a map is sorted by its keys, then its keys are compared and arranged according to the type of sorting required (ascending or descending) and the values are also arranged accordingly. For Example, if the Map [c=2, z=9, d=4, a=6] is sorted on its keys in ascending order, the map is re-arranged to [a=6, c=2, d=4, z=9].

    static void sortByKey() {
	Map unsortedMap = new LinkedHashMap<>();
	unsortedMap.put("K1", 20);
	unsortedMap.put("K3", 5);
	unsortedMap.put("K9", 6);
	unsortedMap.put("K2", 10);
        System.out.println("Unsorted Map is : "+unsortedMap);
	Map sortedMap = new LinkedHashMap();
	unsortedMap.entrySet().stream()
			.sorted(Map.Entry. comparingByKey())
				.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));
	System.out.println("Sorted Map is : "+sortedMap);

    }

Output :

Unsorted Map is : {K1=20, K3=5, K9=6, K2=10}
Sorted Map is : {K1=20, K2=10, K3=5, K9=6}

Explanation :

Java 8 has introduced the concept of stream where in you can get a stream with a collection as its source. Stream provides many methods to perform operations on the collection. Stream is defined by java.util.stream.Streaminterface and can be retrieved by calling stream()method on any linear collection.

In the above method, the code which does the sorting is :

   unsortedMap.entrySet().stream() .sorted(Map.Entry. comparingByKey()).
forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

Let’s change it from one liner to step wise for the purpose of understanding.

1. Stream> stream = unsortedMap.entrySet().stream();
2. Stream>stream2 = stream.sorted(Map.Entry.comparingByKey());
3. stream2.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

The above steps may be explained as :

  1. In the first step, we get a stream of map entries by calling stream()on map’s entry set as unsortedMap.entrySet().stream()which returns a java.util.stream.Stream. This stream has a method sorted()which takes an object of type java.util.Comparator.
  2. Now, java 8 has added a new static method comparingByKey()to the  interface java.util.Map.Entrywhich returns a comparator that compares map’s entry on its key. Combining both the above steps, we get a stream whose elements are sorted by keys.
  3. In Step 3, we iterate over the sorted stream by using its forEachOrderedmethod. This method iterates over the stream in the same order in which the elements flow through the stream and takes an object of type java.util.function.Consumerinterface. This is a functional interface having only one method. As such we pass it a Lambda expression which populates a new Map with the elements of the stream in the order of sorting of its keys.

Note : If you are still having trouble in understanding the above code, then try below code snippet without Generic declarations as they make the code more difficult to read and understand. Apply Generics when you grasp the concept.

Map sortedMap = new LinkedHashMap();
Stream stream = unsortedMap.entrySet().stream();
//here generics is required otherwise next line will give a compiler error. Just try removing…
Stream> stream2 = stream.sorted(Map.Entry. comparingByValue());
stream2.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

Sorting By Values

When a map is sorted by its values, then its values are compared and arranged according to the type of sorting required (ascending or descending) and the keys are also arranged accordingly. For Example, if the Map [c=2, z=9, d=4, a=6] is sorted on its values in ascending order, the map is re-arranged to [c=2, d=4, a=6, z=9].

    static void sortByValue() {
	Map unsortedMap = new LinkedHashMap<>();
	unsortedMap.put("K1", 20);
	unsortedMap.put("K3", 5);
	unsortedMap.put("K9", 6);
	unsortedMap.put("K2", 10);
        System.out.println("Unsorted Map is : "+unsortedMap);
	Map sortedMap = new LinkedHashMap();
	unsortedMap.entrySet().stream()
		.sorted(Map.Entry. comparingByValue())
		.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));
	System.out.println("Sorted Map is : "+sortedMap);

	}

Output :

Unsorted Map is : {K1=20, K3=5, K9=6, K2=10}
Sorted Map is : {K3=5, K9=6, K2=10, K1=20}

Explanation :

In the above method, the code which does the sorting is :

unsortedMap.entrySet().stream().sorted(Map.Entry. comparingByValue()) .forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

Let’s change it from one liner to step wise for the purpose of understanding.

1. Stream> stream = unsortedMap.entrySet().stream();
2. Stream>stream2 = stream.sorted(Map.Entry.comparingByValue());
3. stream2.forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

The above steps may be explained as :

  1. In the first step, we get a stream of map entries by calling stream()on map’s entry set as unsortedMap.entrySet().stream()which returns a java.util.stream.Stream. This stream has a method sorted()which takes an object of type java.util.Comparator.
  2. Now, java 8 has added a new static method comparingByValue()to the  interface java.util.Map.Entrywhich returns a comparator which compares map’s entry on its value. Combining both the above steps, we get a stream whose elements are sorted by value.
  3. In Step 3, we iterate over the sorted stream by using its forEachOrderedmethod. This method iterates over the stream in the same order in which the elements flow through the stream and takes an object of type java.util.function.Consumerinterface. This is a functional interface having only one method. As such we pass it a Lambda expression which populates a new Map with the elements of the stream in the order of sorting of its values.

Let’s tweak in :

  1. In both the above methods, the map which contains the sorted key-values is taken to be of type java.util.LinkedHashMap. This is because LinkedHashMap preserves the order in which the elements are inserted into it. Thus, it will contain the elements in their order of sorting.
  2. Starting java 8 it is possible to have static and default methods in interfaces.
  3. The methods comparingByKey()and comparingByValue()must be called on elements which are mutually comparable otherwise a java.lang.ClassCastExceptionwill be thrown.

For any doubts, further clarifications, feedback…do make use of the space provided below.

6 Comments

Leave a Reply