Ermias Asghedom
Ermias Asghedom

Reputation: 95

How do I use generics with HashMap?

I have two methods, one returns a HashMap of <Integer,String> and the other returns a HashMap of <Integer, Spanned>. Is there a way of using generics to make them into just one method?

public static Map<Integer, Spanned> queryGMGText() throws ParseException {
    ParseQuery<ParseObject> positionQuery = ParseQuery.getQuery("AndroidGMGContent");
    positionQuery.whereExists("position");
    List<ParseObject> ParsePositionResult = positionQuery.find();

    final Map<Integer,Spanned> appText = new HashMap<Integer,Spanned>();

    for (int i = 0; i < ParsePositionResult.size(); i++) {
        appText.put(ParsePositionResult.get(i).getInt("position"), Html.fromHtml(ParsePositionResult.get(i).getString("appText")));
    }

    return appText;
}

public static Map<Integer, String> queryGMG(String field) throws ParseException {
    ParseQuery<ParseObject> positionQuery = ParseQuery.getQuery("AndroidGMGContent");
    positionQuery.whereExists("position");
    List<ParseObject> ParsePositionResult = positionQuery.find();

    final Map<Integer,String> fieldMap = new HashMap<Integer,String>();

    for (int i = 0; i < ParsePositionResult.size(); i++) {
        fieldMap.put(ParsePositionResult.get(i).getInt("position"), ParsePositionResult.get(i).getString(field));
    }

    return fieldMap;
}

and if so, how would I instantiate and call them? Currently I'm doing it this way (from another class):

Map<Integer,Spanned> appTextMap = new HashMap<Integer,Spanned>();
    try {
        appTextMap = ParseContent.queryGMGText();
    } catch (ParseException e) {
        e.printStackTrace();
    }
// now I can use it, i.e.
Spanned s = appTextMap.get(1);

Upvotes: 1

Views: 205

Answers (2)

raffian
raffian

Reputation: 32086

This uses a single map, requires no explicit casting, but does require knowing the type for each key. Maybe not a perfect fit, but maybe this gives you some ideas to build the right solution? Hope it helps,

public class CustomMap {

      private Map<String, Object> _map;

      public CustomMap(){
         _map = new HashMap<String, Object>();  
      }  

      public <T> void setTypeValueByKey(Integer key, T value) {
         _map.put(key.toString(), value);
      }

      public <T> T getTypeValueByKey(Class<T> klass, Integer key) {
         return klass.cast(_map.get(key.toString()));
      }

      public static void main(String[] o){
         CustomMap map = new CustomMap();
         map.setTypeValueByKey(new Integer(1), new Spanned() );
         map.setTypeValueByKey(new Integer(2), new String("foo"));         

         Spanned spanned = 
           map.getTypeValueByKey(Spanned.class, new Integer(1));
         String foo = 
           map.getTypeValueByKey(String.class, new Integer(2));                  
      }

   static class Spanned{}
}

So you have three options:

  • explicit casting using Map<Integer,Object>, jkschneider's solution
  • aspects of my solution above
  • or, Map<Integer,<? extends MyBaseClass>>, where Spanned and a String-like class extends MyBaseClass

Upvotes: 0

Jonathan Schneider
Jonathan Schneider

Reputation: 27757

Strictly answering the question:

Since there is no commonality in the inheritance tree of Spanned and String, you would have to alter the methods to return Map<Integer, Object> and then could:

try {
    Map<Integer, Object> appTextMap = ParseContent.queryGMGText();
    // now I can use it, i.e.
    Spanned s = (Spanned) appTextMap.get(1);
} catch (ParseException e) {
    e.printStackTrace();
}

This kind of defeats the purpose of generics of course, but serves to shine a light on the true problem here.

Reconsidering the original code:

Of course it seems far better to rewrite the whole thing to something like the following. The only difference between the two functions is the Html.forHtml(..) call. Let's assume for a moment (without loss of generality) that you really want the String and not Spanned:

public static Map<Integer, String> queryGMGAppText() throws ParseException {
    return queryGMG("appText");
}

public static Map<Integer, String> queryGMG(String field) throws ParseException {
    ParseQuery<ParseObject> positionQuery = ParseQuery.getQuery("AndroidGMGContent");
    positionQuery.whereExists("position");
    List<ParseObject> ParsePositionResult = positionQuery.find();

    final Map<Integer,String> fieldMap = new HashMap<Integer,String>();

    for (int i = 0; i < ParsePositionResult.size(); i++) {
        fieldMap.put(ParsePositionResult.get(i).getInt("position"), ParsePositionResult.get(i).getString(field));
    }

    return fieldMap;
}

Perhaps you don't really need queryGMGAppText() at all. Are you calling it in so many places that it is important to have this convenience method?

Upvotes: 1

Related Questions