简体   繁体   中英

Storing specific data types in hashmap

I have to use a map which stores keys of type Integer, String and Long only. One solution: To store type Object and in put method check with instanceof operator. Is there any better solution, maybe with enum

You can use a map and storing Long as String into it

or you can use two different hashmap and duplicate put/get methods. If you have two types, it is probably for two different things, and having two different map should probably be the correct answer

Create a class that has a map as a member and add methods that will store and retrieve int and long as Strings.

class MyMap {
    private Map mabObject = Map<String, Object>;

    public void add(long key, Object value) {
        mapObject.put(Long.toString(key),value);
    }

    public void add(String key, Object value) {
        mapObject.put(key, value);
    }

    public Object get(long key) {
        return mapObject.get(Long.toString(key));
    }

    public Object get(String key) {
        return mapObject.get(key);
    }
}

I agree with Paul Boddington's comment, and the need of such trick shows that code smells.

Just for a funny excercise (not for production code) I've made an example that shows what we can do in compile time for limiting types of keys in a map.

For example we can create a wrapper allowing only values of specific classes.

common/map/Wrap.java

package common.map;

import java.util.Arrays;
import java.util.List;

public class Wrap<T> {
  private T value;

  private Wrap(T value){
    this.value = value;
  }

  public T get() {
    return this.value;
  }

  /*
   * it's important to implement this method
   * if we intend to use Wrap instances as map's key
   *
   * and it's needed to see that hash codes are computing differently in different classes,
   * and depending on `allowedClasses` contents we can face some unexpected collisions
   * so if you care of performance - test your maps usage accurately
   */
  public int hashCode() {
    return this.value.hashCode();
  }

  /*
   * static
   */

  private static List<Class> allowedClasses = Arrays.asList(Long.class, String.class);

  public static <T> Wrap<T> create(Class<? extends T> clazz, T value) {

    if (!allowedClasses.contains(clazz)) {
      throw new IllegalArgumentException("Unexpected class " + clazz);
    }

    return new Wrap<>(value);
  }

  public static <T> Wrap<T> create(AllowedClasses allowedClass, T value) {
    return create(allowedClass.clazz, value);
  }

  public enum AllowedClasses {
    LONG(Long.class),
    STRING(String.class);

    private Class clazz;

    AllowedClasses(Class clazz) {
      this.clazz = clazz;
    }
  }
}

And let's run it

common/map/Example.java

package common.map;

import common.map.Wrap.AllowedClasses;

import java.util.HashMap;
import java.util.Map;

public class Example {

  public static void main(String... args) {

    Map<Wrap, Object> map = new HashMap<>();

    // next two lines create wrappers for values of types we added to enum AllowedClasses
    // but since enums cannot have type parameters, we are not able to check
    // if the second parameter type is compatible with a type associated with given enum value
    // so I think usage of enum is useless for your purpose
    Wrap<?> valLong0 = Wrap.create(AllowedClasses.LONG, "the string in place of Long is OK");
    Wrap<?> valString0 = Wrap.create(AllowedClasses.STRING, 12345);


    // from the next lines you can see how we can use the Wrap class to keep
    // only allowed types to be associated with the map keys

    Wrap<Long> valLong = Wrap.create(Long.class, 1L); // legal
    Wrap<String> valString = Wrap.create(String.class, "abc"); // legal

    Wrap<String> valWrong = Wrap.create(String.class, 123); // doesn't compile

    Wrap<Object> valWrong2 = Wrap.create(Object.class, 123); // compiles but throws exception in runtime

    Object obj = ThirdParty.getObjectOfUnknownClass();
    Wrap<?> valDynamic = Wrap.create(obj.getClass(), obj); //  compiles but MAYBE throws exception in runtime


    // so we get to this point only if all the wrappers are legal,
    // and we can add them as keys to the map

    map.put(valLong, new Object());
    map.put(valString, new Object());
    map.put(valDynamic, new Object());
  }
}
HashMap<DataType1,DataType2>hm = new HashMap<DataType1,DataType2>();

or

Map<DataType1,DataType2> m = new HashMap<DataType1,DataType2>();

m.put(key, value);

Instead of DataType1 & DataType2 you can add Integer , String , Long ,etc. and use the put(key,value) method to enter key and values into the HashMap.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM