-3

I have a question regarding the initiation of ArrayList in Java.

As far as I know I have to specify the type of my ArrayList when initialize it. For example:

ArrayList<String> names = new ArrayList<String>();

or

ArrayList<String> names = new ArrayList<>();

However, when I want to write a code to return an ArrayList of List, which is from the values of a map Map<String, List> map = new HashMap<>(); If I tried to use the following, error happens

return new ArrayList<>(map.values())

or

return new ArrayList<List<String>>(map.values())

Instead, I can only use the one, without the <>.

return new ArrayList(map.values())

Could anyone let me know when I should or should not use the <> when I initialize an ArrayList(or any other objects)?

The original code is as written below

    public List<List<String>> groupAnagrams(String[] strs) {
        if (strs.length == 0) return new ArrayList<>();
        Map<String, List> res = new HashMap<>();
        for (String s : strs) {
            char[] charArray = s.toCharArray();
            Arrays.sort(charArray);
            String key = String.valueOf(charArray);
            if (!res.containsKey(key)) res.put(key, new ArrayList());
            res.get(key).add(s);
        }
        
        return new ArrayList<List<String>>(res.values());
    }
  • 3
    _always_, really. – Eugene Sep 24 '21 at 14:16
  • 3
    `new ArrayList(map.values())` is a [raw type](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it). That is, a type for which all further generic type-checking is disabled. Don't use it. – Andy Turner Sep 24 '21 at 14:16
  • 1
    should be `Map>` – kofemann Sep 24 '21 at 14:21
  • Your HashMap's values are `List`, which is basically `List`. It could hold a String, an Integer and a StringBuilder for all we know. That's why trying to create a `List` from those values doesn't work - they aren't necessarily all Strings. We can't be sure it does hold strings. Change the map definition to `Map>`, then revert the return to `return new ArrayList<>(map.values());` – Michael Sep 24 '21 at 14:22
  • @Michael "which is basically `List`" please don't say things like this: it's entirely valid to use a `List`, and have heterogeneously-typed elements. The problem is that `List` *isn't* a `List`, it's not type checked, and the non-type checking is viral through its returned values. Saying "is basically" implies they are similar enough in function that it's OK to use either, which it's not. – Andy Turner Sep 24 '21 at 14:24
  • "*Saying "is basically" implies it's the same*" Disagree – Michael Sep 24 '21 at 14:26
  • @Michael what do you mean then? – Andy Turner Sep 24 '21 at 14:28

2 Answers2

1
public List<List<String>> groupAnagrams(String[] strs) {
  ...
  Map<String, List> res = new HashMap<>();
  ...
  res.put(key, new ArrayList());
  ...
  return new ArrayList<List<String>>(res.values());
}

The problem here is that res.values() isn't a Collection<List<String>>, which is what would be required: it's a Collection<List>.

The elements of res.values() are raw types: you've used List without specifying the type parameters.

Raw types disable type checking, meaning you can end up putting things into collections with types you don't want.

Every time you use a generic type, make sure it has type parameters (or diamonds, if allowed:

public List<List<String>> groupAnagrams(String[] strs) {
  ...
  Map<String, List<String>> res = new HashMap<>();
  ...
  res.put(key, new ArrayList<>());
  ...
  return new ArrayList<>(res.values());
}
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
-1

Because the type of map value is List , but you define the type of list value is string.

And suggest use guava Multimap instead of Map<String ,List>

JZH
  • 47
  • 2