Java 8 – Sort a Map by Value

Introduction

Sorting a map by its values is a common requirement in Java, especially when you need to rank data, display the most significant entries first, or process the data in a particular order. Unlike sorting by keys, which can be easily done using a TreeMap, sorting by values requires a different approach since the Map interface does not provide a direct method for value-based sorting.

Java 8 introduced the Stream API, which offers a powerful and flexible way to sort maps by their values. In this guide, we will explore how to sort a map by its values using different methods in Java 8, including handling ties (where multiple keys have the same value) and using custom comparators for more complex sorting requirements.

Table of Contents

  • Problem Statement
  • Solution Steps
  • Java Program
    • Sorting a Map by Value Using Streams
    • Sorting a Map by Value in Descending Order
    • Sorting a Map by Value with a Custom Comparator
  • Advanced Considerations
  • Conclusion

Problem Statement

The task is to create a Java program that:

  • Accepts a map of key-value pairs.
  • Sorts the map by its values.
  • Outputs the sorted map.

Example 1:

  • Input: Map {1: "Banana", 2: "Apple", 3: "Orange"}
  • Output: Sorted Map {2: "Apple", 1: "Banana", 3: "Orange"}

Example 2:

  • Input: Map {"Banana": 2, "Apple": 3, "Orange": 1}
  • Output: Sorted Map {"Orange": 1, "Banana": 2, "Apple": 3}

Solution Steps

  1. Create a Map: Start with an unsorted map of key-value pairs.
  2. Sort the Map by Value: Use the Stream API to sort the map entries by their values.
  3. Handle Custom Sorting: Implement a custom comparator if necessary to define a specific order.
  4. Display the Result: Print the sorted map.

Java Program

Sorting a Map by Value Using Streams

The most straightforward way to sort a map by its values in Java 8 is by using the Stream API. This method involves converting the map’s entry set to a stream, sorting the stream by values, and collecting the sorted entries back into a map.

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Java 8 - Sort a Map by Value Using Streams
 * Author: https://www.rameshfadatare.com/
 */
public class SortMapByValueUsingStreams {

    public static void main(String[] args) {
        // Step 1: Create an unsorted map
        Map<Integer, String> unsortedMap = Map.of(
            1, "Banana",
            2, "Apple",
            3, "Orange"
        );

        // Step 2: Sort the map by values using streams
        Map<Integer, String> sortedMap = unsortedMap.entrySet()
            .stream()
            .sorted(Map.Entry.comparingByValue())
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (oldValue, newValue) -> oldValue,
                LinkedHashMap::new
            ));

        // Step 3: Display the result
        System.out.println("Sorted Map: " + sortedMap);
    }
}

Output

Sorted Map: {2=Apple, 1=Banana, 3=Orange}

Explanation

  • The entrySet() method converts the map into a set of key-value pairs.
  • The stream() method creates a stream from the entry set.
  • The sorted(Map.Entry.comparingByValue()) method sorts the stream by the values.
  • The sorted entries are then collected back into a LinkedHashMap to maintain the order.

Sorting a Map by Value in Descending Order

To sort a map by values in descending order, you can modify the comparator used in the sorting process.

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Java 8 - Sort a Map by Value in Descending Order
 * Author: https://www.rameshfadatare.com/
 */
public class SortMapByValueDescending {

    public static void main(String[] args) {
        // Step 1: Create an unsorted map
        Map<String, Integer> unsortedMap = Map.of(
            "Banana", 2,
            "Apple", 3,
            "Orange", 1
        );

        // Step 2: Sort the map by values in descending order
        Map<String, Integer> sortedMap = unsortedMap.entrySet()
            .stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (oldValue, newValue) -> oldValue,
                LinkedHashMap::new
            ));

        // Step 3: Display the result
        System.out.println("Sorted Map: " + sortedMap);
    }
}

Output

Sorted Map: {Apple=3, Banana=2, Orange=1}

Explanation

  • The sorted(Map.Entry.comparingByValue().reversed()) method sorts the stream by values in descending order.
  • The sorted entries are collected into a LinkedHashMap to maintain the order after sorting.

Sorting a Map by Value with a Custom Comparator

If you need to implement a custom sorting logic, you can provide a custom comparator to the sorted() method.

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Java 8 - Sort a Map by Value with a Custom Comparator
 * Author: https://www.rameshfadatare.com/
 */
public class SortMapByValueWithCustomComparator {

    public static void main(String[] args) {
        // Step 1: Create an unsorted map
        Map<Integer, String> unsortedMap = Map.of(
            1, "Banana",
            2, "Apple",
            3, "Orange"
        );

        // Step 2: Sort the map by values using a custom comparator
        Map<Integer, String> sortedMap = unsortedMap.entrySet()
            .stream()
            .sorted((entry1, entry2) -> entry1.getValue().length() - entry2.getValue().length())
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (oldValue, newValue) -> oldValue,
                LinkedHashMap::new
            ));

        // Step 3: Display the result
        System.out.println("Sorted Map: " + sortedMap);
    }
}

Output

Sorted Map: {2=Apple, 1=Banana, 3=Orange}

Explanation

  • The custom comparator (entry1, entry2) -> entry1.getValue().length() - entry2.getValue().length() sorts the entries by the length of their values.
  • The sorted entries are collected into a LinkedHashMap to maintain the sorted order.

Advanced Considerations

  • Handling Ties: If two or more keys have the same value, the sorting will retain their original order unless a secondary sorting criterion is provided. You can add additional sorting criteria if needed.

  • Null Values: If your map contains null values, be cautious during sorting as null values can cause NullPointerException. Handle nulls explicitly in your comparator if necessary.

  • Performance Considerations: Sorting a map by values using streams is generally efficient for typical map sizes. However, for very large maps, test the performance to ensure it meets your application’s requirements.

Conclusion

This guide provides methods for sorting a map by its values in Java 8, covering approaches with the Stream API and custom comparators. Sorting maps by value is a common requirement when you need to rank or display data in a specific order, and Java 8 provides powerful tools to perform this task efficiently and flexibly. Depending on your specific use case, you can choose the method that best fits your needs for sorting maps by value in Java.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top