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,691
  • 5
  • 29
  • 48

3 Answers3

6

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
  • 10,402
  • 4
  • 41
  • 68
  • 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
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
  • 195,030
  • 44
  • 313
  • 345
  • 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
  • 190,799
  • 110
  • 376
  • 555