Skip to content

Commit f418078

Browse files
committed
ImmutableMap — Internal Working
Signed-off-by: https://github.com/Someshdiwan <[email protected]>
1 parent 9e34463 commit f418078

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
ImmutableMap — Internal Working
2+
3+
Java provides multiple ways to create "immutable" or unmodifiable maps. There are two common patterns:
4+
1) an immutable *view* over a mutable map (`Collections.unmodifiableMap(...)`),
5+
2) truly immutable maps created by factory methods (`Map.of(...)` and `Map.ofEntries(...)`).
6+
Each has different internal characteristics and use-cases.
7+
8+
1. Collections.unmodifiableMap(map)
9+
----------------------------------
10+
- What it is:
11+
Creates an *immutable view* (a read-only wrapper) of an existing Map instance.
12+
13+
- Internal working:
14+
- `Collections.unmodifiableMap(m)` returns a wrapper object (an instance of a private static class
15+
inside `Collections`) that implements `Map`.
16+
- The wrapper delegates all read operations (get, containsKey, entrySet, etc.) directly to the underlying map instance.
17+
- Mutating calls (put, remove, clear, putAll, etc.) on the wrapper throw `UnsupportedOperationException`.
18+
- The wrapper is a *shallow* wrapper — it does not copy entries. It only prevents modifications via the wrapper reference.
19+
20+
- Important consequences:
21+
- If the original map (`map1`) is modified directly (not via the wrapper), those changes are visible through the wrapper.
22+
- The wrapper is lightweight and cheap because it only stores a reference to the original map.
23+
- Not a true immutable snapshot — use only for defensive read-only sharing when you control who can modify the original.
24+
25+
- Use-cases:
26+
- Provide read-only access to an internal data structure without copying.
27+
- Protect a map from modification by API consumers while still allowing internal updates.
28+
29+
- ASCII (conceptual)
30+
[map1 (modifiable)] <---- wrapper delegates reads ---- [unmodifiableMap (view)]
31+
put("A",1) --> map1 changes visible via unmodifiableMap.get("A")
32+
33+
2. Map.of()
34+
-----------
35+
- What it is:
36+
- Factory methods introduced in Java 9 to create truly immutable small maps.
37+
- Example: `Map.of("A", 1, "B", 2)`.
38+
39+
- Internal working:
40+
- `Map.of(...)` implementations create an internal compact, immutable map representation (not a wrapper).
41+
- The returned instance contains its own internal arrays/structures for keys and values.
42+
- It is not backed by any external map; it cannot be changed after creation.
43+
- Typically optimized for small fixed sizes (special-cased implementations for 0..10 entries).
44+
45+
- Important consequences:
46+
- Truly immutable — no external modification possible and no view semantics.
47+
- Attempting `put` or `remove` throws `UnsupportedOperationException`.
48+
- Very memory- and CPU-efficient for small constant maps.
49+
- Limited convenience overloads: `Map.of` has overloaded variants up to 10 key-value pairs.
50+
51+
- Use-cases:
52+
- Small fixed configuration maps or constants defined at startup.
53+
- When you want a true immutable map with no risk of external mutation.
54+
55+
- ASCII (conceptual)
56+
[Map.of instance] -> independent immutable storage of {A=1, B=2}
57+
Changes to other maps do not affect it.
58+
59+
3. Map.ofEntries()
60+
------------------
61+
- What it is:
62+
- Also Java 9; flexible factory method that accepts many `Map.entry(...)` items and returns a truly immutable map.
63+
- Not limited to 10 entries.
64+
65+
- Internal working:
66+
- Builds an independent immutable internal structure from the provided entries.
67+
- Likely uses an optimized internal representation to store the entries compactly (array-based or similar).
68+
- Not a wrapper; it is a separate object with no references to any source map.
69+
70+
- Important consequences:
71+
- Same immutability guarantees as `Map.of`.
72+
- Useful when you need more than 10 entries or want to construct an immutable map programmatically.
73+
74+
- Use-cases:
75+
- Large constant maps at initialization, configuration mapping, read-only lookup tables.
76+
77+
Comparison summary (quick)
78+
--------------------------
79+
- Backing:
80+
- `Collections.unmodifiableMap`: wrapper around existing map (delegates reads).
81+
- `Map.of` / `Map.ofEntries`: independent immutable instances (no backing map).
82+
83+
- Mutability:
84+
- `unmodifiableMap`: prevents modification via wrapper but underlying map can still change.
85+
- `Map.of` / `Map.ofEntries`: fully immutable (cannot change at all).
86+
87+
- Memory & performance:
88+
- `unmodifiableMap`: minimal overhead, cheap to create.
89+
- `Map.of` / `Map.ofEntries`: optimized internal structures, efficient for lookups, slightly higher creation cost but immutable.
90+
91+
Practical examples and notes
92+
----------------------------
93+
- When to choose which:
94+
- Want to expose internal map read-only while still updating it internally? Use `Collections.unmodifiableMap`.
95+
- Need a true constant map that never changes and is safe to share across threads without synchronization? Use `Map.of` or `Map.ofEntries`.
96+
- Need >10 entries and immutability? Use `Map.ofEntries`.
97+
98+
- Thread-safety:
99+
- `Map.of` / `Map.ofEntries` are inherently thread-safe (immutable).
100+
- `Collections.unmodifiableMap` is thread-safe for reads only if the underlying map is thread-safe; otherwise concurrent modifications of the backing map can lead to race conditions.
101+
102+
- Example patterns:
103+
- Defensive API:
104+
`public Map<K,V> getSettings() { return Collections.unmodifiableMap(this.settings); }`
105+
(internal code can still update `settings`.)
106+
107+
- Constant config:
108+
`private static final Map<String,Integer> LIMITS = Map.of("A", 1, "B", 2);`
109+
110+
ASCII diagram: wrapper vs independent
111+
------------------------------------
112+
Wrapper (unmodifiableMap):
113+
+-----------------+ +--------------------+
114+
| unmodifiableMap | --delegates--> | backing HashMap |
115+
| (throws on put) | | {A=1, B=2} |
116+
+-----------------+ +--------------------+
117+
118+
Independent immutable (Map.of / Map.ofEntries):
119+
+-------------------------+
120+
| immutableMap (Map.of) |
121+
| internal storage {A=1} |
122+
+-------------------------+
123+
(no link to any other map, cannot change)
124+
125+
Final takeaways
126+
---------------
127+
- `Collections.unmodifiableMap` is a cheap defensive view; use when you must share a mutable map read-only.
128+
- `Map.of` and `Map.ofEntries` produce true immutable maps suitable for constants and thread-safe shared data.
129+
- Choose the one that matches whether you need a view-on-existing-data or a separate immutable snapshot.

0 commit comments

Comments
 (0)