Java Generics and Collections

I have a question about Java Generics and Collections. It was considered good practice to declare the collection as follows:

List<String> catNames = new ArrayList<String>(); 

because you can change the type of List and not worry about breaking the rest of your code. But when I try to do this:

 private static Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, ArrayList<Issue>>(); 

javac complains

 Type mismatch: cannot convert from HashMap<ResultsAggregator.IssueType,ArrayList<Issue>> to HashMap<ResultsAggregator.IssueType,List<Issue>> 

In addition, it is completely legal:

 private static Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, List<Issue>>(); 

which seems even more confusing because List is an interface, not a concrete class. What's going on here? Is this a type erase problem?

+4
source share
2 answers

If it were legal to compile such code, you could secretly insert an element from other types in the HashMap :

 HashMap<IssueType, List<Issue>> a = new HashMap<IssueType, ArrayList<Issue>>(); a.put(someIssue, new SomeClassThatImplementsListOfIssueButIsNotArrayList()); 

what you do not expect. ArrayList<String> is a List<String> , but this is not enough for this code to be safe and correct. To be safe, this also requires a List<String> be an ArrayList<String> , which means that the generic type argument is not covariant here.

Your last code is legal because nothing requires the type parameter to be a concrete class. Likewise, nothing requires a field to be of an abstract type.

+8
source

There is no reason to specify an ArrayList in the second example. It doesn't actually create a list, so it's best to place the interface there. Then you can call the following just fine.

 Map<IssueType, List<Issue>> orphanedAttrMap = new HashMap<IssueType, List<Issue>>(); orphanedAttrMap.put(IssueType.TYPE, new ArrayList<Issue>()); 
+4
source

Source: https://habr.com/ru/post/1332581/


All Articles