118

Context

I need to return a reference to a map that I'm using for a data cache, and I'd like to make sure nobody can modify their reference.

Question

I've seen lots of references to UnmodifiableMap and ImmutableMap online, but I don't see anything comparing/contrasting them. I figure there is a good reason that Google/Guava created their own version - can someone tell me what it is?

John Humphreys
  • 37,047
  • 37
  • 155
  • 255
  • 2
    this might help , http://stackoverflow.com/questions/8892350/immutable-vs-unmodifiable-collection – Jimmy Mar 25 '14 at 13:51
  • 1
    Apparently my Google terms sucked. I'll accept the first answer when the clock rolls over since they're all the same :). – John Humphreys Mar 25 '14 at 13:55

4 Answers4

222

An unmodifiable map may still change. It is only a view on a modifiable map, and changes in the backing map will be visible through the unmodifiable map. The unmodifiable map only prevents modifications for those who only have the reference to the unmodifiable view:

Map<String, String> realMap = new HashMap<String, String>();
realMap.put("A", "B");

Map<String, String> unmodifiableMap = Collections.unmodifiableMap(realMap);

// This is not possible: It would throw an 
// UnsupportedOperationException
//unmodifiableMap.put("C", "D");

// This is still possible:
realMap.put("E", "F");

// The change in the "realMap" is now also visible
// in the "unmodifiableMap". So the unmodifiableMap
// has changed after it has been created.
unmodifiableMap.get("E"); // Will return "F". 

In contrast to that, the ImmutableMap of Guava is really immutable: It is a true copy of a given map, and nobody may modify this ImmutableMap in any way.

Update:

As pointed out in a comment, an immutable map can also be created with the standard API using

Map<String, String> immutableMap = 
    Collections.unmodifiableMap(new LinkedHashMap<String, String>(realMap)); 

This will create an unmodifiable view on a true copy of the given map, and thus nicely emulates the characteristics of the ImmutableMap without having to add the dependency to Guava.

Community
  • 1
  • 1
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • 10
    1up for not just linking to the documentation, but providing an example as well. – Martin Nielsen Mar 25 '14 at 14:00
  • Good example, thank you for the help :). – John Humphreys Mar 25 '14 at 18:33
  • 37
    It's worth noting that a truly immutable copy of the original backing map can be achieved with `Map unmodifiableMap = Collections.unmodifiableMap(new HashMap<>(realMap));` Achieves the same result as ImmutableMap without the dependency on third party libraries. – Lorkenpeist Aug 30 '16 at 03:15
  • @Lorkenpeist Good point. In practice, I would recommend `Collections.unmodifiableMap(new LinkedHashMap<>(realMap));` to keep the iteration order intact (but there may be cases where this doesn't matter). In any case, I'm regularly doing this, and would prefer it over `ImmutableMap` (particularly if Guava is not already a dependency anyhow). There may be justifications for still using `ImmutableMap` (e.g. using it as a return type, to show in an interface that the returned map is *immutable*, but one cannot make a general recommendation here) – Marco13 Sep 27 '16 at 14:17
  • 2
    Now with Java 9, you can use: `Map unmodifiableMap = Map.ofEntries(entry("A","B"), entry("C","D"), entry("E","F"));` which is more beautiful to my mind – Steph Sep 11 '18 at 13:54
  • Immutable map is only useful if you are setting up static config but IMO there are much better patterns to encapsulate the same. Also Map is truly immutable if both value and keys are immutable. Immutable map wont protect in case value returned is mutable. In most of the use case Collections.unmodifiable map should suffice, again not a good pattern to return raw maps for any function invocation. – Jany Dec 10 '19 at 16:19
11

Have a look at ImmutableMap JavaDoc: doc

There is information about that there:

Unlike Collections.unmodifiableMap(java.util.Map), which is a view of a separate map which can still change, an instance of ImmutableMap contains its own data and will never change. ImmutableMap is convenient for public static final maps ("constant maps") and also lets you easily make a "defensive copy" of a map provided to your class by a caller.

sP_
  • 1,738
  • 2
  • 15
  • 29
Jakub H
  • 2,130
  • 9
  • 16
2

Guava Documentation

The JDK provides Collections.unmodifiableXXX methods, but in our opinion, these can be unwieldy and verbose; unpleasant to use everywhere you want to make defensive copies unsafe: the returned collections are only truly immutable if nobody holds a reference to the original collection inefficient: the data structures still have all the overhead of mutable collections, including concurrent modification checks, extra space in hash tables, etc.

spaaarky21
  • 6,524
  • 7
  • 52
  • 65
Eric Stein
  • 13,209
  • 3
  • 37
  • 52
2

ImmutableMap does not accept null values whereas Collections.unmodifiableMap() does. In addition it will never change after construction, while UnmodifiableMap may. From the JavaDoc:

An immutable, hash-based Map with reliable user-specified iteration order. Does not permit null keys or values.

Unlike Collections.unmodifiableMap(java.util.Map), which is a view of a separate map which can still change, an instance of ImmutableMap contains its own data and will never change. ImmutableMap is convenient for public static final maps ("constant maps") and also lets you easily make a "defensive copy" of a map provided to your class by a caller.

tharindu_DG
  • 8,900
  • 6
  • 52
  • 64
Harmlezz
  • 7,972
  • 27
  • 35