0
# Immutable Collections
1
2
Thread-safe, unmodifiable collection implementations with factory methods compatible with Java 9+ collection APIs but available for earlier Java versions. This package provides high-performance immutable collections that ensure data integrity and thread safety.
3
4
## Capabilities
5
6
### Immutable Lists
7
8
Create and manipulate immutable lists with various factory methods and guaranteed thread safety.
9
10
```java { .api }
11
/**
12
* Factory methods for creating immutable lists
13
*/
14
public final class Lists {
15
/**
16
* Create an empty immutable list
17
* @return Empty immutable list
18
*/
19
public static <E> List<E> of();
20
21
/**
22
* Create an immutable list with one element
23
* @param element The single element
24
* @return Immutable list containing the element
25
*/
26
public static <E> List<E> of(E element);
27
28
/**
29
* Create an immutable list with two elements
30
* @param e1 First element
31
* @param e2 Second element
32
* @return Immutable list containing the elements
33
*/
34
public static <E> List<E> of(E e1, E e2);
35
36
/**
37
* Create an immutable list with three elements
38
* @param e1 First element
39
* @param e2 Second element
40
* @param e3 Third element
41
* @return Immutable list containing the elements
42
*/
43
public static <E> List<E> of(E e1, E e2, E e3);
44
45
/**
46
* Create an immutable list with four elements
47
* @param e1 First element
48
* @param e2 Second element
49
* @param e3 Third element
50
* @param e4 Fourth element
51
* @return Immutable list containing the elements
52
*/
53
public static <E> List<E> of(E e1, E e2, E e3, E e4);
54
55
/**
56
* Create an immutable list with five elements
57
* @param e1 First element
58
* @param e2 Second element
59
* @param e3 Third element
60
* @param e4 Fourth element
61
* @param e5 Fifth element
62
* @return Immutable list containing the elements
63
*/
64
public static <E> List<E> of(E e1, E e2, E e3, E e4, E e5);
65
66
/**
67
* Create an immutable list from variable arguments
68
* @param elements Variable number of elements
69
* @return Immutable list containing the elements
70
*/
71
@SafeVarargs
72
public static <E> List<E> of(E... elements);
73
74
/**
75
* Create an immutable list by copying from an existing collection
76
* @param collection Source collection to copy from
77
* @return Immutable list containing all elements from the collection
78
* @throws NullPointerException if collection is null
79
*/
80
public static <E> List<E> copyOf(Collection<? extends E> collection);
81
82
/**
83
* Collector to create immutable lists from streams
84
* @return Collector that accumulates to an immutable list
85
*/
86
public static <E> Collector<E, ?, List<E>> toList();
87
}
88
```
89
90
**Usage Example:**
91
92
```java
93
import aQute.bnd.unmodifiable.Lists;
94
import java.util.List;
95
import java.util.stream.Stream;
96
97
// Create immutable lists
98
List<String> empty = Lists.of();
99
List<String> single = Lists.of("hello");
100
List<String> multiple = Lists.of("alpha", "beta", "gamma");
101
List<Integer> numbers = Lists.of(1, 2, 3, 4, 5);
102
103
// Copy from existing collection
104
List<String> originalList = Arrays.asList("a", "b", "c");
105
List<String> immutableCopy = Lists.copyOf(originalList);
106
107
// Use with streams
108
List<String> processed = Stream.of("HELLO", "WORLD", "JAVA")
109
.map(String::toLowerCase)
110
.collect(Lists.toList());
111
112
// Attempt to modify throws UnsupportedOperationException
113
try {
114
multiple.add("delta"); // This will throw
115
} catch (UnsupportedOperationException e) {
116
System.out.println("Cannot modify immutable list");
117
}
118
119
// Safe iteration (no concurrent modification concerns)
120
for (String item : multiple) {
121
System.out.println(item); // Thread-safe iteration
122
}
123
```
124
125
### Immutable Maps
126
127
Create and manipulate immutable maps with type safety and performance optimization.
128
129
```java { .api }
130
/**
131
* Factory methods for creating immutable maps
132
*/
133
public final class Maps {
134
/**
135
* Create an empty immutable map
136
* @return Empty immutable map
137
*/
138
public static <K, V> Map<K, V> of();
139
140
/**
141
* Create an immutable map with one key-value pair
142
* @param key The key
143
* @param value The value
144
* @return Immutable map containing the entry
145
*/
146
public static <K, V> Map<K, V> of(K key, V value);
147
148
/**
149
* Create an immutable map with two key-value pairs
150
* @param k1 First key
151
* @param v1 First value
152
* @param k2 Second key
153
* @param v2 Second value
154
* @return Immutable map containing the entries
155
*/
156
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2);
157
158
/**
159
* Create an immutable map with three key-value pairs
160
* @param k1 First key
161
* @param v1 First value
162
* @param k2 Second key
163
* @param v2 Second value
164
* @param k3 Third key
165
* @param v3 Third value
166
* @return Immutable map containing the entries
167
*/
168
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3);
169
170
/**
171
* Create an immutable map with four key-value pairs
172
* @param k1 First key
173
* @param v1 First value
174
* @param k2 Second key
175
* @param v2 Second value
176
* @param k3 Third key
177
* @param v3 Third value
178
* @param k4 Fourth key
179
* @param v4 Fourth value
180
* @return Immutable map containing the entries
181
*/
182
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4);
183
184
/**
185
* Create an immutable map with five key-value pairs
186
* @param k1 First key
187
* @param v1 First value
188
* @param k2 Second key
189
* @param v2 Second value
190
* @param k3 Third key
191
* @param v3 Third value
192
* @param k4 Fourth key
193
* @param v4 Fourth value
194
* @param k5 Fifth key
195
* @param v5 Fifth value
196
* @return Immutable map containing the entries
197
*/
198
public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5);
199
200
/**
201
* Create an immutable map from variable map entries
202
* @param entries Variable number of map entries
203
* @return Immutable map containing the entries
204
* @throws IllegalArgumentException if duplicate keys are found
205
*/
206
@SafeVarargs
207
public static <K, V> Map<K, V> ofEntries(Map.Entry<? extends K, ? extends V>... entries);
208
209
/**
210
* Create an immutable map by copying from an existing map
211
* @param map Source map to copy from
212
* @return Immutable map containing all entries from the source map
213
* @throws NullPointerException if map is null
214
*/
215
public static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map);
216
217
/**
218
* Create a map entry (convenience method for use with ofEntries)
219
* @param key The key
220
* @param value The value
221
* @return Immutable map entry
222
*/
223
public static <K, V> Map.Entry<K, V> entry(K key, V value);
224
}
225
```
226
227
**Usage Example:**
228
229
```java
230
import aQute.bnd.unmodifiable.Maps;
231
import java.util.Map;
232
233
// Create immutable maps
234
Map<String, Integer> empty = Maps.of();
235
Map<String, Integer> single = Maps.of("one", 1);
236
Map<String, Integer> multiple = Maps.of(
237
"alpha", 1,
238
"beta", 2,
239
"gamma", 3
240
);
241
242
// Create using entries
243
Map<String, String> config = Maps.ofEntries(
244
Maps.entry("host", "localhost"),
245
Maps.entry("port", "8080"),
246
Maps.entry("timeout", "30000")
247
);
248
249
// Copy from existing map
250
Map<String, Integer> originalMap = new HashMap<>();
251
originalMap.put("x", 10);
252
originalMap.put("y", 20);
253
Map<String, Integer> immutableCopy = Maps.copyOf(originalMap);
254
255
// Attempt to modify throws UnsupportedOperationException
256
try {
257
multiple.put("delta", 4); // This will throw
258
} catch (UnsupportedOperationException e) {
259
System.out.println("Cannot modify immutable map");
260
}
261
262
// Safe concurrent access
263
multiple.forEach((key, value) -> {
264
System.out.println(key + " = " + value); // Thread-safe iteration
265
});
266
```
267
268
### Immutable Sets
269
270
Create and manipulate immutable sets with guaranteed uniqueness and performance optimization.
271
272
```java { .api }
273
/**
274
* Factory methods for creating immutable sets
275
*/
276
public final class Sets {
277
/**
278
* Create an empty immutable set
279
* @return Empty immutable set
280
*/
281
public static <E> Set<E> of();
282
283
/**
284
* Create an immutable set with one element
285
* @param element The single element
286
* @return Immutable set containing the element
287
*/
288
public static <E> Set<E> of(E element);
289
290
/**
291
* Create an immutable set with two elements
292
* @param e1 First element
293
* @param e2 Second element
294
* @return Immutable set containing the elements
295
* @throws IllegalArgumentException if duplicate elements are provided
296
*/
297
public static <E> Set<E> of(E e1, E e2);
298
299
/**
300
* Create an immutable set with three elements
301
* @param e1 First element
302
* @param e2 Second element
303
* @param e3 Third element
304
* @return Immutable set containing the elements
305
* @throws IllegalArgumentException if duplicate elements are provided
306
*/
307
public static <E> Set<E> of(E e1, E e2, E e3);
308
309
/**
310
* Create an immutable set with four elements
311
* @param e1 First element
312
* @param e2 Second element
313
* @param e3 Third element
314
* @param e4 Fourth element
315
* @return Immutable set containing the elements
316
* @throws IllegalArgumentException if duplicate elements are provided
317
*/
318
public static <E> Set<E> of(E e1, E e2, E e3, E e4);
319
320
/**
321
* Create an immutable set with five elements
322
* @param e1 First element
323
* @param e2 Second element
324
* @param e3 Third element
325
* @param e4 Fourth element
326
* @param e5 Fifth element
327
* @return Immutable set containing the elements
328
* @throws IllegalArgumentException if duplicate elements are provided
329
*/
330
public static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5);
331
332
/**
333
* Create an immutable set from variable arguments
334
* @param elements Variable number of elements
335
* @return Immutable set containing unique elements
336
* @throws IllegalArgumentException if duplicate elements are provided
337
*/
338
@SafeVarargs
339
public static <E> Set<E> of(E... elements);
340
341
/**
342
* Create an immutable set by copying from an existing collection
343
* @param collection Source collection to copy from
344
* @return Immutable set containing all unique elements from the collection
345
* @throws NullPointerException if collection is null
346
*/
347
public static <E> Set<E> copyOf(Collection<? extends E> collection);
348
349
/**
350
* Collector to create immutable sets from streams
351
* @return Collector that accumulates to an immutable set
352
*/
353
public static <E> Collector<E, ?, Set<E>> toSet();
354
}
355
```
356
357
**Usage Example:**
358
359
```java
360
import aQute.bnd.unmodifiable.Sets;
361
import java.util.Set;
362
import java.util.stream.Stream;
363
364
// Create immutable sets
365
Set<String> empty = Sets.of();
366
Set<String> single = Sets.of("unique");
367
Set<String> multiple = Sets.of("alpha", "beta", "gamma");
368
Set<Integer> numbers = Sets.of(1, 2, 3, 4, 5);
369
370
// Copy from existing collection (removes duplicates)
371
List<String> listWithDuplicates = Arrays.asList("a", "b", "a", "c", "b");
372
Set<String> uniqueSet = Sets.copyOf(listWithDuplicates); // Contains: a, b, c
373
374
// Use with streams to remove duplicates
375
Set<String> processed = Stream.of("HELLO", "WORLD", "HELLO", "JAVA")
376
.map(String::toLowerCase)
377
.collect(Sets.toSet()); // Contains: hello, world, java
378
379
// Duplicate detection at creation time
380
try {
381
Set<String> invalid = Sets.of("a", "b", "a"); // This will throw
382
} catch (IllegalArgumentException e) {
383
System.out.println("Duplicate elements not allowed");
384
}
385
386
// Efficient membership testing
387
boolean containsAlpha = multiple.contains("alpha"); // O(1) lookup
388
```
389
390
### Immutable Collection Implementations
391
392
The underlying implementations provide specific guarantees and optimizations.
393
394
```java { .api }
395
/**
396
* Immutable list implementation with guaranteed thread safety
397
*/
398
public class ImmutableList<E> implements List<E> {
399
// All mutating operations throw UnsupportedOperationException
400
// Thread-safe for concurrent read access
401
// Optimized for memory usage and performance
402
}
403
404
/**
405
* Immutable map implementation with guaranteed thread safety
406
*/
407
public class ImmutableMap<K, V> implements Map<K, V> {
408
// All mutating operations throw UnsupportedOperationException
409
// Thread-safe for concurrent read access
410
// Optimized hash table implementation
411
}
412
413
/**
414
* Immutable set implementation with guaranteed thread safety
415
*/
416
public class ImmutableSet<E> implements Set<E> {
417
// All mutating operations throw UnsupportedOperationException
418
// Thread-safe for concurrent read access
419
// Optimized for fast membership testing
420
}
421
422
/**
423
* Immutable map entry implementation
424
*/
425
public class ImmutableEntry<K, V> implements Map.Entry<K, V> {
426
/**
427
* Get the key (never null if key was non-null at creation)
428
*/
429
@Override
430
public K getKey();
431
432
/**
433
* Get the value (may be null if value was null at creation)
434
*/
435
@Override
436
public V getValue();
437
438
/**
439
* Attempt to set value (always throws UnsupportedOperationException)
440
*/
441
@Override
442
public V setValue(V value); // Always throws
443
}
444
```
445
446
### Stream Integration
447
448
Seamless integration with Java 8 streams for functional programming patterns.
449
450
```java { .api }
451
// Collectors are provided for stream termination
452
List<String> immutableList = stream.collect(Lists.toList());
453
Set<String> immutableSet = stream.collect(Sets.toSet());
454
455
// Custom collectors can be built for maps
456
Collector<Person, ?, Map<String, Integer>> toNameAgeMap =
457
Collector.of(
458
HashMap::new,
459
(map, person) -> map.put(person.getName(), person.getAge()),
460
(map1, map2) -> { map1.putAll(map2); return map1; },
461
Maps::copyOf
462
);
463
```
464
465
**Usage Example:**
466
467
```java
468
// Process data with streams and collect to immutable collections
469
List<String> processedList = rawData.stream()
470
.filter(Objects::nonNull)
471
.map(String::trim)
472
.filter(s -> !s.isEmpty())
473
.map(String::toLowerCase)
474
.distinct()
475
.sorted()
476
.collect(Lists.toList());
477
478
Set<String> uniqueWords = text.stream()
479
.flatMap(line -> Arrays.stream(line.split("\\s+")))
480
.map(word -> word.replaceAll("[^a-zA-Z]", ""))
481
.filter(word -> !word.isEmpty())
482
.collect(Sets.toSet());
483
```
484
485
### Performance Characteristics
486
487
The immutable collections are optimized for different use cases:
488
489
**Lists:**
490
- **Random Access**: O(1) for get operations
491
- **Memory Overhead**: Minimal - array-based storage
492
- **Creation Cost**: O(n) copying cost, then immutable
493
- **Iteration**: High performance, no synchronization needed
494
495
**Maps:**
496
- **Lookup**: O(1) average case hash table lookup
497
- **Memory Overhead**: Hash table overhead plus immutability guarantees
498
- **Creation Cost**: O(n) for copying and hash computation
499
- **Iteration**: Efficient key, value, and entry iteration
500
501
**Sets:**
502
- **Membership Testing**: O(1) average case
503
- **Memory Overhead**: Hash set overhead
504
- **Creation Cost**: O(n) with duplicate detection
505
- **Iteration**: Efficient element iteration
506
507
### Thread Safety Guarantees
508
509
All immutable collections provide strong thread safety guarantees:
510
511
1. **No Synchronization Required**: Multiple threads can safely read concurrently
512
2. **No Defensive Copying**: Collections never change, so references can be shared freely
513
3. **Safe Publication**: Once constructed, can be safely published to other threads
514
4. **Iterator Safety**: Iterators never throw ConcurrentModificationException
515
5. **Memory Visibility**: All threads see the same consistent state
516
517
### Comparison with Standard Collections
518
519
**vs ArrayList/HashMap/HashSet:**
520
- Immutable collections prevent accidental modification
521
- Thread-safe without synchronization overhead
522
- Can be safely cached and reused
523
- Eliminate defensive copying needs
524
525
**vs Collections.unmodifiableList/Map/Set:**
526
- True immutability (not just unmodifiable views)
527
- Better performance for read operations
528
- No risk of underlying collection modification
529
- Optimized implementations
530
531
**vs Guava ImmutableList/Map/Set:**
532
- Similar functionality and guarantees
533
- Reduced dependency footprint
534
- Consistent API with Java 9+ collection factories
535
- OSGi-friendly packaging
536
537
### Best Practices
538
539
1. **Prefer Small Collections**: Factory methods are optimized for small collections (≤5 elements)
540
2. **Use copyOf for Large Collections**: More efficient than of(...) for many elements
541
3. **Cache Expensive Results**: Immutable collections are perfect for caching
542
4. **Return Immutable Collections**: From public APIs to prevent external modification
543
5. **Stream Integration**: Use provided collectors for clean functional style
544
6. **Null Handling**: Collections accept null values but not null keys (maps)
545
546
### Migration from Mutable Collections
547
548
```java
549
// Before: Mutable collections requiring defensive copying
550
public List<String> getItems() {
551
return new ArrayList<>(this.items); // Defensive copy
552
}
553
554
// After: Return immutable collection directly
555
public List<String> getItems() {
556
return this.items; // Already immutable, no copying needed
557
}
558
559
// Before: Synchronized access to shared collections
560
private final List<String> items = Collections.synchronizedList(new ArrayList<>());
561
562
// After: Build once, share safely
563
private final List<String> items = Lists.copyOf(buildInitialItems());
564
```
565
566
This approach eliminates many common threading issues and simplifies concurrent programming by making data immutable by default.