2

The structure is like this:

public interface ItemList{ }

public enum ItemList1 implements ItemList {

    Apple,
    Orange;
}

public enum ItemList2 implements ItemList {

    Banana,
    Grapes;
}

and 5 more such enums

The requirement is to use these enums as Keys in a Map, and in those Maps I have put key as:

public Class SomeClass {
private Map<ItemList, OtherObject> objectList;
//other code
}

The ItemList which goes into the map is decided on runtime. And I need to use a sorted Map like TreeMap for other operations. So, the TreeMap is unable to compare the key enums obviously because I have declared them as ItemList supertype.

So, I searched other questions and did something like this so that enums could use their compareTo method:

public interface ItemList<SelfType extends ItemList<SelfType>> extends Comparable<SelfType>{ }

public enum ItemList1 implements ItemList<SelfType> {
     //enum values
}

But this doesn't solve the problem. I am still getting the same "ClassCastException" when I tried to retrieve a TreeMap which had my enums as Keys.

Please suggest if I am doing anything wrongly here, or what can be an other way to solve this purpose?

EDIT: Link to the solution which I followed, but it's not working: How to implement an interface with an enum, where the interface extends Comparable?

EDIT 2 Problem identified. Sorry guys. My map was getting populated with different types of enums as keys, when all the keys should belong to same type for sorting to work.

Community
  • 1
  • 1
Anmol Gupta
  • 2,797
  • 9
  • 27
  • 43
  • I don't understand why the map couldn't sort the keys. As long as it contains only instances of ItemList1, or only instances of ItemList2, everything should work fine. And from your description, it seems to be the case. – JB Nizet Apr 08 '15 at 17:00
  • You can't put constants from two different enums in a single `TreeMap` as keys. Basically you can't compare them. – Rohit Jain Apr 08 '15 at 17:03
  • @JBNizet Yes, same thing is bothering me. I checked it so many times. I followed answer to this question http://stackoverflow.com/questions/7160980/how-to-implement-an-interface-with-an-enum-where-the-interface-extends-comparab – Anmol Gupta Apr 08 '15 at 17:25
  • @RohitJain The Map is being populated with only one type of List. But, which enum will it get populated with is being decided on runtime. – Anmol Gupta Apr 08 '15 at 17:27
  • @AnmolGupta Then you can't get a `ClassCastException`. – Rohit Jain Apr 08 '15 at 17:27
  • @RohitJain Thanks Rohit! I checked thoroughly and yes the map was getting populated with different types of list as keys and hence the exception. – Anmol Gupta Apr 08 '15 at 18:17

2 Answers2

1

Well, you already found out that it was the actual content of the Map, not the declaration of the classes that caused the exception, but it’s worth noting that using collections comparing these enums is easier than you think.

E.g. TreeMap doesn’t care whether its declared Generic type has a comparable key or not. If you have class declarations like

public interface ItemList{ }
public enum ItemList1 implements ItemList { Apple, Orange }
public enum ItemList2 implements ItemList { Banana, Grapes }

you can simply use it as

TreeMap<ItemList,Object> tm=new TreeMap<>();
tm.put(ItemList1.Apple, "A");
tm.put(ItemList1.Orange, "O");
System.out.println(tm.get(ItemList1.Apple)+" is for "+ItemList1.Apple);
tm.clear();
tm.put(ItemList2.Banana, "B");
tm.put(ItemList2.Grapes, "G");
System.out.println(tm.get(ItemList2.Banana)+" is for "+ItemList2.Banana);

without problems; it even works if you declare the map as TreeMap<Object,Object>.

Note that some methods require comparable types when requesting natural order by not specifying a Comparator, e.g. with the type declarations above,

List<Object> list=Arrays.<Object>asList(ItemList1.Orange,ItemList1.Apple,ItemList1.Orange);
Collections.sort(list);

does not compile, however, you can easily circumvent it by requesting the natural order via a null Comparator:

Collections.sort(list, null); // compiles and works

So it’s not necessary to mess around with complicated type declarations like ItemList<SelfType extends ItemList<SelfType>> in most cases.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thanks Holger, this added to my knowledge of using TreeMap. Just to make sure I get it correctly, so whenever i don't have a specific comparator for Keys of a treemap, it would just take the natural order while sorting right? And for the methods which require comparator to be mentioned explicitly, I can just pass null as the comparator for natural order being still considered as the sorted order ? Thanks! – Anmol Gupta Apr 13 '15 at 05:09
  • Right, not specifying a `Comparator` always implies natural ordering and the overloads omitting the parameter usually enforce `Comparable` elements while methods taking a `Comparator` don’t. I can’t speak for every possible method, but the documentation of [`Collections.sort`](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#sort-java.util.List-java.util.Comparator-) and [`Collections.binarySearch`](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#binarySearch-java.util.List-T-java.util.Comparator-) clearly specify the behavior for a `null` comparator. – Holger Apr 13 '15 at 08:14
0

It sounds like what you should be doing is having

 private Map<? extends ItemList, OtherObject> objectList;

...to indicate objectList is a specific map of some subtype of ItemList, and then

 objectList = new TreeMap<ItemList1, OtherObject>();

or

 objectList = new TreeMap<ItemList2, OtherObject>();

to declare it as some specific type of ItemList. (You may have to store it temporarily as a Map<ItemListN, OtherObject> while you populate it, but then you can put it in objectList.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Thanks Louis for the quick response, the problem was that Map got populated with different types of enums at a point, and I asked it to compare apples with Bananas so it threw the exception :) – Anmol Gupta Apr 08 '15 at 18:21