3

Evening!

I have the following Map:

HashMap<String, ArrayList> myMap = new HashMap<String, ArrayList>();

I then added the following data to it:

ArrayList myList = new ArrayList();
myList.add("Test 1");
myList.add("Test 2");
myList.add("Test 3");
myMap.put("Tests", myList);

This left me with the following data:

Key: Tests


Values: Test 1, Test 2, Test 3

My question is, how do I then add new values on to my already existing key? So for example, how could I add the value "Test 4" onto my key "Tests".

Thanks.

Joe
  • 4,877
  • 5
  • 30
  • 51

3 Answers3

7

I'd recommend using Map#computeIfAbsent, to always ensure retrieving a List from the map:

private final Map<String, List<String>> example = new HashMap<>();

private List<String> getList(String key) {
    return this.example.computeIfAbsent(key, k -> new ArrayList<>());
}

//elsewheres
getList("test").add("foobar");
getList("test").forEach(System.out::println); // "foobar"

This means that if the map doesn't contain an entry for the key, it will use the provided lambda to generate a new value for the key and return that.

Rogue
  • 11,105
  • 5
  • 45
  • 71
  • 1
    But that's putting the value in the map right? I am not sure I like the idea of putting data in a collection if we're using a **getter** method. – dabadaba May 09 '16 at 21:33
  • It places the value if it is absent, the idea is you're defaulting. If the resource isn't available for you, it will make it and provide the new resource. Perfectly valid. – Rogue May 14 '16 at 19:29
  • Coming back here years later, there is also `Map#getOrDefault` if you don't want to preserve the list / return a mutable reference. This will simply return the default object without putting it in the map. This of course means that mutating the return result would be pointless, which in some cases may be appropriate. – Rogue Aug 23 '23 at 12:26
4

Simply get the list from the map and then add the element to the list:

ArrayList list = myMap.get("Tests");
list.add("Test4");

There are some other things that can be remarked about your code. First of all, don't use the raw type ArrayList. Use generics:

HashMap<String, ArrayList<String>> myMap = new HashMap<String, ArrayList<String>>();

ArrayList<String> myList = new ArrayList<String>();
myList.add("Test 1");
myList.add("Test 2");
myList.add("Test 3");
myMap.put("Tests", myList);

Second, program to interfaces, not implementations. In other words, program using interfaces Map and List rather than the implementations HashMap and ArrayList. This is a well-known OO programming principle, which makes it for example easier to switch to a different implementation, if necessary.

Map<String, List<String>> myMap = new HashMap<String, List<String>>();

List<String> myList = new ArrayList<String>();
myList.add("Test 1");
myList.add("Test 2");
myList.add("Test 3");
myMap.put("Tests", myList);

Finally, a syntax tip: if you're using Java 7 or newer you can use <> and you don't have to repeat the type arguments:

Map<String, List<String>> myMap = new HashMap<>();

List<String> myList = new ArrayList<>();
myList.add("Test 1");
myList.add("Test 2");
myList.add("Test 3");
myMap.put("Tests", myList);

myMap.get("Tests").add("Test 4");
Community
  • 1
  • 1
Jesper
  • 202,709
  • 46
  • 318
  • 350
  • 4
    Or even `myMap.computeIfAbsent("Tests", k -> new ArrayList<>())`, for the next question of "why did I get a `NullPointerException` with a different key". – Boris the Spider May 09 '16 at 21:12
  • @BoristheSpider wow I didn't know this one. Was it introduced in Java 8? Also is there a similar one for `put`? – dabadaba May 09 '16 at 21:14
  • @dabadaba, yes - as it has a lambda. What would the one for `put` do exactly? – Boris the Spider May 09 '16 at 21:15
  • 1
    @BoristheSpider Are you sure ```getOrDefault``` can take a supplier? [HashMap Javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html#getOrDefault-java.lang.Object-V-). There are no overloads. – Jorn Vernee May 09 '16 at 21:16
  • Thank you so much for your help everyone! I will make sure to follow this information. – Joe May 09 '16 at 21:17
  • @BoristheSpider That would be a nice feature though ;) I was wondering why I never heard about it (in my mind maybe some 3rd party libray or something). – Jorn Vernee May 09 '16 at 21:18
  • @BoristheSpider imagine you have a `Map>`. If you want to add a new value to a existing or not key you need to check if `containsKey(k)` and if the value is an initalized list (not `null`). So I am talking about a method that would a) create a new list, add the element to it and then set is as `k`s value or b) simply add the element to the existing value list – dabadaba May 09 '16 at 21:19
  • @dabadaba isn't that _exactly_ what the above does? – Boris the Spider May 09 '16 at 21:19
  • @BoristheSpider no... what you said is a "getter", I am talking about a "setter". edit: Wait you just changed the method, I was talking about `getOrDefault`... – dabadaba May 09 '16 at 21:20
  • @dabadaba you want to `get` a value from a `Map`, and if there is no value present `compute` a new value a `put` it into the `Map`. The method then either returns the `get` or the new value. Finally you do whatever you want with that value - in your example it's a `List` so you `add`. I'm not convinced you've read [the documentation](https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function-). – Boris the Spider May 09 '16 at 21:22
  • @BoristheSpider and I am convinced you edited your comment without letting me know so what I said above referred to the content of your comments before your edit ;) – dabadaba May 09 '16 at 21:24
1
import java.util.*;

class M {
    public static void main( String ... args ) {
        List<String> l = new ArrayList<>();
        l.add("Test 1");
        l.add("Test 2");
        l.add("Test 3");

        Map<String,List<String>> m = new HashMap<>();
        m.put("Tests", l );

        // some time later that day ... 
        m.computeIfAbsent("Tests", k -> new ArrayList<>()).add("Test 4");
        System.out.println(m);
    }
}
OscarRyz
  • 196,001
  • 113
  • 385
  • 569