Question

I want to create a sorted Map. I created a map with below code and first I checked this object and add this object to list. But when I try check second object it gives ClassCastException.

java.lang.ClassCastException: java.lang.String cannot be cast to myapplication.Student

Here is my code;

Map students = new TreeMap(new Comparator<Student>() {
    @Override
    public int compare(Student s1, Student s2) {
        if(s1.getName() == null || s2.getName() == null){
            return -1;
        }
        return s1.getName().compareTo(s2.getName());
    }
});


Student student = (Student) students.get("23123");
if (student == null) {
    student= new Student("321312", "sfsfsfs");
    students.put("23123", student);
}

Student student2 = (Student) students.get("42131");//this line throws exception
if (student2 == null) {
    student2 = new Student("421321", "dgdfs");
    students.put("42131", student2);
}

My Student.java class;

public class Student {

    private String name;
    private String number;

    //const, getters and setters.

}
Was it helpful?

Solution

In TreeMap the Comparator is to compare the key rather than the value. The first get and put succeeded because the map is empty, and don't need to invoke your comparator. But the second get requires the comparator to compare the key with the existing key. Your input key is String type while the comparator process it as Student type. Then a ClassCastException is thrown.

Declare your map as:

Map<String, Student> students = new TreeMap<String, Student>();

then it will work. Note that you don't need to provide a Comparetor for String key type because String is already Comparable.

OTHER TIPS

You don't show us how you populate the Map. So my general advice is to use Generics:

Map<String, Student> students = new TreeMap<>(...);

Then casting is not necessary.

Avoid using raw types in collections. In such cases you are not sure what is actually going into your collection (like Map, List etc.) As a result, you need to add a cast while retrieving elements from the Map which is vulnerable to ClassCastException as you are not sure about the object being retrieved.

Try using generics like this:

Map<String, Student> students = new TreeMap<String, Student>();
Student student2= (Student) students.get("42131");

I feel at first time when the block of code will execute there would be no value associated with the key "42131" so it'll return null. Which you try to cast with Student class.

Map students = new TreeMap(...);

This generic map will accept any type of Object key,value pair. So you must use generic to make type-safe.

like

Map<String, Student> students = new TreeMap<>(...);

This students map is type safe to string type of key and Student type of value.

And Exception you are getting just because of you have added some string against that key.

I found another approach, just extend TreeMap and override compare method. It looks like this:

class StudentMap<K extends String, T extends Student> 
    extends TreeMap<String, Student> implements Comparator<String> {

    @Override
    public int compare(String key1, String key2) {
        if (key1 == null || key2 == null) {
            return -1;
        }
        return this.get(key1).getName().compareTo(this.get(key2).getName());
    }
}

And you can use it like this:

final Map<String, Student> students = new StudentMap<>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top