I find that when using java collections, especially when writing utility methods using generics, that my code is often ugly and bloated, full of null checks, nested loops, and repetition. Focusing on this one example, I’d like ideas for improvement.
Assume we have an EnumMap whose values are lists of ratings. For example, say the enums themselves represent fruit, and each value represents a list ratings given by different people.
APPLE -> [1, 3, 4]
ORANGE -> [2, 0, 5]
John rated apple 1, Mary rated apple 3, Steve rated apple 4
John rated orange 2, Mary rated orange 0, Steve rated orange 5
Note the specific names are irrelevant and provided only to clarify the setup
Now we want to write a utility method that accepts a data structure like the one above, and returns a list of each person’s favorite fruit. Thus the expected result for the above sample data would be: [ORANGE, APPLE, ORANGE since 2 > 1, 3 > 0, and 5 > 4.
Below is my current method for doing this. I’d like an equally (or more) efficient, but cleaner, way to write the same algorithm.
Thanks!
public class MyListUtil {
public static <K extends Enum<K>, T extends Object & Comparable<? super T>> List<K> maxKeysByIndex(EnumMap<K, List<T>> enumMap) {
Iterator<K> keysIter = enumMap.keySet().iterator();
int sizeOfAllLists = enumMap.get(keysIter.next()).size();
List<K> ret = new ArrayList<K>();
for (int i=0; i<sizeOfAllLists; i++) {
keysIter = enumMap.keySet().iterator();
K maxIndexKey = null;
T maxIndexVal = null;
while (keysIter.hasNext()){
K curKey = keysIter.next();
T curVal = enumMap.get(curKey).get(i);
if (maxIndexVal == null || curVal.compareTo(maxIndexVal) > 0) {
maxIndexVal = curVal;
maxIndexKey = curKey;
}
}
ret.add(maxIndexKey);
}
return ret;
}
}
If you need a lot of methods that all operate on the same generic types, I think you could put the helper methods for
KandTinto a class, and then only specify the full generic type for the class as a whole. To use them you would create an object of that class, and then call the methods from it.The object would be stateless, but it gives you a syntactic way to put all the verbosity into a single place.
You could try putting the inner loop into a separate method, say:
I’ve also changed it to
for-eachsyntax, removing some of the iterator cruft.