Home > Mobile >  Java map with lists of different types as values
Java map with lists of different types as values

Time:12-10

public static void main(String[] args) {
  Map<Integer, List<?>> map = new HashMap<>();
  List<String> strings = new ArrayList<>();
  List<Integer> integers = new ArrayList<>();
  map.put(1, strings);
  map.put(2, integers);
  
  fill("abc", map.get(1));   // red underline
}

public static <T> void fill(T obj, List<T> list) {
    list.add(obj);
}

My IDE marks the call to fill with a red underline and shows this message:

reason: no instance(s) of type variable(s) exist so that String conforms to capture of ? 
inference variable T has incompatible bounds: 
equality constraints: capture of ? 
lower bounds: String

How do I code a map that can have lists of different types as values?

Edit: Assume the type of the element to be added is only available at runtime. For example, you read a file that has both strings and ints (one per row). So, you can't cast the list to the actual type in code.

CodePudding user response:

You can, but it's inadvisable to do so, as you (and the compiler) can no longer reason about what is really inside your map. Type safety exists so that you are much less likely to write code that crashes, such as accidentally trying to add an integer into a List of Strings or a String into a List of Integers.

This seems to be trying to use Maps for something that they aren't really made for. Consider creating a new class type instead that properly encapsulates the data that you're trying to model:

public class MyType {
    private List<String> strings = new ArrayList<>();
    private List<Integer> integers = new ArrayList<>();

    public List<String> getStrings() { return strings; }
    public List<Integer> getIntegers() { return integers; }
}

fill("abc", myType.getStrings()); //will work fine
fill("abc", myType.getIntegers()); //compiler error
fill(5, myType.getIntegers()); //great
fill(5, myType.getStrings()); //boo

This way the compiler helps you write safe code, and you (and anybody else that may need to work with your code in the future) will have an immediate understanding of what that code is supposed to do, especially if you use more expressive names, such as naming the type Student, getStrings becomes getSubjectsTaken() and getIntegers might become getAttendanceRecord(). Takes on a completely new dimension then.

CodePudding user response:

If you want a list that can store data of any type, use List<Object>.

public static void main(String[] args) {
  Map<Integer, List<Object>> map = new HashMap<>();
  List<Object> strings = new ArrayList<>();
  List<Object> integers = new ArrayList<>();
  map.put(1, strings);
  map.put(2, integers);
  
  map.get(1).add("abc");
}
  • Related