I want to implement something like this:

Map<String, List<String>> m = new HashMap<>();
for (... in ...) {
    String key = ...;
    String val = ...;
    m.merge(key, Lists.newArrayList(val), (oldValue, newValue) -> {
       if (oldValue.size() == 1) {
            oldValue.addAll(newValue);
       } else {
            // log error
       }
       return oldValue;
    });
}

so does it safe to modify the oldValue here ? I don't want to get trouble when someday the jvm is updated.

3 Replies 3

Yea It's safe but for that usecase better use something like computeIfAbsent

Map<String, List<String>> m = new HashMap<>();
for (... in ...) {
    String key = ...;
    String val = ...;
    
    List<String> list = m.computeIfAbsent(key, k -> new ArrayList<>());
    if (list.size() == 1) {
        list.add(val);
    } else if (list.isEmpty()) {
        list.add(val);
    } else {
        // log error
    }
}

It's safe.

This statement in the Javadoc:

Otherwise, replaces the associated value with the results of the given remapping function

means that it doesn't actually matter whether oldValue really is the "old value" if that's the value that you return: the return value is the value which will be inserted into the map afterwards.

It's safe. Map has no idea what the types are of the keys and values it contains. As far as its implementation is concerned, they are both Object, and Object does not expose any relevant state.

When you write oldValue.anything you're 'following the pointer' (in javaspeak, 'dereferencing'). From the point of view of the hashmap, you're not changing anything. Or rather, the things you might change cannot possibly affect the map.

Ordinarily you'd then think that oldValue = x would be a problem; that's not 'dereferencing', that's modifying the pointer directly. Except that's not true either: Java is pass-by-value, so that oldValue is a copy of the pointer the hashmap internally uses. You can change it all day, the map cannot witness any of these changes thus by definition that cannot break anything.

Finally, return oldValue; - that does have an effect, and the spec indicates what that is. What you're doing fits within that spec, and specs are guaranteed future proof (or rather, OpenJDK's backwards compatibility promises aren't absolute, but if OpenJDK really thinks its a good idea to modify how maps work, that would break all existing code anyway, you can't prepare for such a thing).

Thus, we end up at the answer: What you're doing is guaranteed safe. Not becauser the spec suggests it, no, because java itself implies no imaginable future change to any map impl could possibly be affected.

Your Reply

By clicking “Post Your Reply”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.