Pages

Saturday, December 11, 2021

Java TreeMap Comparator

1. Overview

In this tutorial, We'll learn how to add a custom comparator to the TreeMap in java to sort by key and also sort by values.

If you are new to java comparators, please read an in-depth article on Java comparators with java 8 stream api. 

Java TreeMap Comparator



2. Java TreeMap Comparator - Sort by Keys By Default


First, let us how to sort the keys with a comparator in java. But, before that just see how treemap sorts by default with keys.

Example 1
package com.javaprogramto.collections.treemap.comparator;

import java.util.Map;
import java.util.TreeMap;

public class TreeMapComparatorExample {

	public static void main(String[] args) {

		Map<String, Integer> designationSalaryInUSD = new TreeMap<>();

		designationSalaryInUSD.put("Software Engineer", 150_000);
		designationSalaryInUSD.put("Senior Software Engineer", 210_000);
		designationSalaryInUSD.put("Manger", 300_000);
		designationSalaryInUSD.put("Lead Engineer", 250_000);

		System.out.println("treemap - " + designationSalaryInUSD);
	}
}

Output
treemap - {Lead Engineer=250000, Manger=300000, Senior Software Engineer=210000, Software Engineer=150000}

From the output, we can see that the treemap is sorted by keys by default even though we did not provide any comparator for it. Because of this reason, TreeMap is called as SortedMap.


3. Java TreeMap Comparator - Custom objects Sort by keys


But when the key objects are added for the user-defined or custom class objects then the default treemap sort does not work like Strings. In this case, we need to pass the comparator logic to the TreeMap constructor as in the below example. But, first, let us see without passing the comparator and what would be the output?

Example 2
package com.javaprogramto.collections.treemap.comparator;

import java.util.Map;
import java.util.TreeMap;

public class TreeMapComparatorCustomObjectsExample {

	public static void main(String[] args) {

		Map<Customer, Integer> customerAgeMap = new TreeMap<>();

		customerAgeMap.put(new Customer(123, "D"), 30);
		customerAgeMap.put(new Customer(102, "B"), 70);
		customerAgeMap.put(new Customer(135, "A"), 40);
		customerAgeMap.put(new Customer(130, "C"), 50);

		System.out.println("treemap - " + customerAgeMap);

	}
}

class Customer {
	private int id;
	private String name;

	public Customer(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}

	// setters and getters

	@Override
	public String toString() {
		return "Customer [id=" + id + ", name=" + name + "]";
	}
}

Output

This program execution has ended with an exception saying ClassCastException.

Exception in thread "main" java.lang.ClassCastException: class com.javaprogramto.collections.treemap.comparator.Customer cannot be cast to class java.lang.Comparable (com.javaprogramto.collections.treemap.comparator.Customer is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
	at java.base/java.util.TreeMap.compare(TreeMap.java:1291)
	at java.base/java.util.TreeMap.put(TreeMap.java:536)
	at com.javaprogramto.collections.treemap.comparator.TreeMapComparatorCustomObjectsExample.main(TreeMapComparatorCustomObjectsExample.java:12)

It is saying Customer object can not be cast to the Comparable interface.

But in the case of the key as String type, we did not get any error because, String class implements a Comparable interface and String objects are successfully casted to Comparable interface. This is the reason to not throw any exception when adding any class that implements a Comparable interface.

To fix this class cast exception for the Customer class, we can do 2 things such as the first one is Customer class has to implement a Comparable interface or create the comparator for the Customer class.

Now the topic is a comparator, so let us create the comparator with Customer to sort by id.

Example 3

In this example, the custom comparator is passed to the TreeMap constructor to sort the customer by id.
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;

public class TreeMapComparatorCustomObjectsExample2 {

	public static void main(String[] args) {

		Map<Customer, Integer> customerAgeMap = new TreeMap<>(new Comparator<Customer>() {
			@Override
			public int compare(Customer o1, Customer o2) {
				Integer id1 = o1.getId();
				Integer id2 = o2.getId();
				return id1.compareTo(id2);
			}
		});

		customerAgeMap.put(new Customer(123, "D"), 30);
		customerAgeMap.put(new Customer(102, "B"), 70);
		customerAgeMap.put(new Customer(135, "A"), 40);
		customerAgeMap.put(new Customer(130, "C"), 50);

		System.out.println("treemap with comparator - " + customerAgeMap);

	}
}

Output
treemap - {Customer [id=102, name=B]=70, Customer [id=123, name=D]=30, Customer [id=130, name=C]=50, Customer [id=135, name=A]=40}

Custom comparator to sort the Customer key by name


Example 4
Map<Customer, Integer> customerAgeMap = new TreeMap<>(new Comparator<Customer>() {
	@Override
	public int compare(Customer o1, Customer o2) {
		String name1 = o1.getName();
		String name2 = o2.getName();
		
		return name1.compareTo(name2);
	}
});

Output
treemap - {Customer [id=135, name=A]=40, Customer [id=102, name=B]=70, Customer [id=130, name=C]=50, Customer [id=123, name=D]=30}


4. Java 8 TreeMap Comparator - Custom objects Sort by keys


Comparators can be created with java 8 lambda's also.


Example 5
public class TreeMapComparatorCustomObjectsExample4 {

	public static void main(String[] args) {

		Map<Customer, Integer> customerAgeMap = new TreeMap<>(Comparator.comparing(Customer::getId));

		customerAgeMap.put(new Customer(123, "D"), 30);
		customerAgeMap.put(new Customer(102, "B"), 70);
		customerAgeMap.put(new Customer(135, "A"), 40);
		customerAgeMap.put(new Customer(130, "C"), 50);

		System.out.println("java 8 - treemap sort by id - " + customerAgeMap);
		
		Map<Customer, Integer> customerAgeMap2 = new TreeMap<>(Comparator.comparing(Customer::getName));

		customerAgeMap2.put(new Customer(123, "D"), 30);
		customerAgeMap2.put(new Customer(102, "B"), 70);
		customerAgeMap2.put(new Customer(135, "A"), 40);
		customerAgeMap2.put(new Customer(130, "C"), 50);

		System.out.println("java 8 - treemap sort by name - " + customerAgeMap2);

	}
}

Output
java 8 - treemap sort by id - {Customer [id=102, name=B]=70, Customer [id=123, name=D]=30, Customer [id=130, name=C]=50, Customer [id=135, name=A]=40}
java 8 - treemap sort by name - {Customer [id=135, name=A]=40, Customer [id=102, name=B]=70, Customer [id=130, name=C]=50, Customer [id=123, name=D]=30}


5. Java 8 TreeMap Comparator - Sort by values


Let us sort the same treemap by keys. Here for simplicity, we have taken key as a type of integer.

Map or TreeMap sort by values can be done in different ways but we are doing it differently with TreeSet.

The below code is to sort the treemap by value with the custom comparator logic.


Example 6
import java.util.Comparator;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;

public class TreeMapComparatorByValueExample {

	public static void main(String[] args) {

		// sorted set with the custom comparator
		SortedSet<Map.Entry<Customer, Integer>> sortedset = new TreeSet<>(
				new Comparator<Map.Entry<Customer, Integer>>() {
					@Override
					public int compare(Map.Entry<Customer, Integer> e1, Map.Entry<Customer, Integer> e2) {
						return e1.getValue().compareTo(e2.getValue());
					}
				});

		Map<Customer, Integer> customerAgeMap = new TreeMap<>(Comparator.comparing(Customer::getId));

		customerAgeMap.put(new Customer(123, "D"), 30);
		customerAgeMap.put(new Customer(102, "B"), 70);
		customerAgeMap.put(new Customer(135, "A"), 40);
		customerAgeMap.put(new Customer(130, "C"), 50);

		// adding treemap values to the treeset.
		
		sortedset.addAll(customerAgeMap.entrySet());

		System.out.println("java 8 - treemap sort by value - " + sortedset);

	}
}


Output
java 8 - treemap sort by value - [Customer [id=123, name=D]=30, Customer [id=135, name=A]=40, Customer [id=130, name=C]=50, Customer [id=102, name=B]=70]


6. Conslusion


In this article, we've seen how to add a comparator to TreeMap to sort by keys and values in java and java 8.





No comments:

Post a Comment

Please do not add any spam links in the comments section.