Week 93 — What are unmodifiable collections and how can these be obtained?

Question of the Week #93
What are unmodifiable collections and how can these be obtained?
4 Replies
0x150
0x1503mo ago
Unmodifiable collections are collections where mutating operations throw UnsupportedOperationExceptions. It is possible to get unmodifiable collections using the Collections.unmodifiableList(someList), Collections.unmodifiableSet(someSet), Collections.unmodifiableMap(someMap), Collections.unmodifiableCollection(someCollections) and similar methods. These are typically views on other collections meaning that if the original collection is modified, these changes are reflected in the unmodifiable collection view.
List<String> someList = new ArrayList<>();
someList.add("Hello");
List<String> unmodifiableView = Collections.unmodifiableList(someList);
System.out.println(unmodifiableView);//[Hello]
someList.add("World");
System.out.println(unmodifiableView);//[Hello, World]
unmodifiableView.add("...");//UnsupportedOperationException
List<String> someList = new ArrayList<>();
someList.add("Hello");
List<String> unmodifiableView = Collections.unmodifiableList(someList);
System.out.println(unmodifiableView);//[Hello]
someList.add("World");
System.out.println(unmodifiableView);//[Hello, World]
unmodifiableView.add("...");//UnsupportedOperationException
On the other hand, immutable collections don't change when the collection used for their constructions are modified. These can be obtained using the List.copyOf(someCollection), Map.copyOf(someCollection) and Set.copyOf(someCollection) methods:
List<String> someList = new ArrayList<>();
someList.add("Hello");
List<String> immutableList = List.copyOf(someList);
System.out.println(immutableList);//[Hello]
someList.add("World");
System.out.println(immutableList);//[Hello]
System.out.println(someList);//[Hello, World]
immutableList.add("...");//UnsupportedOperationException
List<String> someList = new ArrayList<>();
someList.add("Hello");
List<String> immutableList = List.copyOf(someList);
System.out.println(immutableList);//[Hello]
someList.add("World");
System.out.println(immutableList);//[Hello]
System.out.println(someList);//[Hello, World]
immutableList.add("...");//UnsupportedOperationException
📖 Sample answer from dan1st
0x150
0x1503mo ago
These types of collections can’t be changed or altered at all. To use them someone would code the collection as unmodifiable however the person wanted to view the collection.
Submission from miamason
0x150
0x1503mo ago
unmodifiable collection is a wrapper around a modifiable collection which other code may still have access to.
Submission from freakybhuvi
0x150
0x1503mo ago
Unmodifiable collections are collections, that can't be modified in any way after creation. They can be obtained by wrapping an existing collection with one of Collection.unmodifiable<...> methods. Example:
List<String> readWriteList = new ArrayList<String>();
// You can add items to the newly created list
readWriteList.add("item1");

List<String> readOnlyList = Collections.unmodifiableList(readWriteList);

// It's forbidden and will throw an UnsupportedOperationException
readOnlyList.add("item2");
List<String> readWriteList = new ArrayList<String>();
// You can add items to the newly created list
readWriteList.add("item1");

List<String> readOnlyList = Collections.unmodifiableList(readWriteList);

// It's forbidden and will throw an UnsupportedOperationException
readOnlyList.add("item2");
As seen in the above example example, trying to modify the collection in any way will throw an UnsupportedOperationException. Now, for a practical example. Let's say you have a class, that needs to hold a list of items. You want users to be able to retrieve the list at any time, but you want to prevent them from adding anything, or you want to implement custom adding logic. So:
public class Items {
private final List<String> list = new ArrayList<>();

public void add(String item) {
if(!list.contains(item) && item.starts("item-")) {
list.add(item);
// Some custom post-add logic
}
}

public List<String> getItemsList() {
// Ensures that the caller can't modify the returned list
return Collections.unmodifiableList(this.list);
}
}
public class Items {
private final List<String> list = new ArrayList<>();

public void add(String item) {
if(!list.contains(item) && item.starts("item-")) {
list.add(item);
// Some custom post-add logic
}
}

public List<String> getItemsList() {
// Ensures that the caller can't modify the returned list
return Collections.unmodifiableList(this.list);
}
}
The above example allows you to precisely control what items can be added to the internal list (in that case allowing only strings starting with "item-"). The user can still retrieve the full list at any time and iterate over it, but they can only modify it with your class's add method. Of course you can wrap all kinds of collections with Collections.unmodifiableCollection(Collection), and even maps: (Collections.unmodifiableMap(Map)). They will all behave the same way, returning the read-only version of the provided collection.
⭐ Submission from java.net.defective

Did you find this page helpful?