Immutable vs Unmodifiable collection

JavaCollectionsImmutability

Java Problem Overview


From the Collections Framework Overview:

> Collections that do not support modification operations (such as add, remove and clear) are referred to as unmodifiable. Collections that are not unmodifiable are modifiable. > > Collections that additionally guarantee that no change in the Collection object will be visible are referred to as immutable. Collections that are not immutable are mutable.

I cannot understand the distinction.
What is the difference between unmodifiable and immutable here?

Java Solutions


Solution 1 - Java

An unmodifiable collection is often a wrapper around a modifiable collection which other code may still have access to. So while you can't make any changes to it if you only have a reference to the unmodifiable collection, you can't rely on the contents not changing.

An immutable collection guarantees that nothing can change the collection any more. If it wraps a modifiable collection, it makes sure that no other code has access to that modifiable collection. Note that although no code can change which objects the collection contains references to, the objects themselves may still be mutable - creating an immutable collection of StringBuilder doesn't somehow "freeze" those objects.

Basically, the difference is about whether other code may be able to change the collection behind your back.

Solution 2 - Java

Basically unModifiable Collection is a view, So indirectly it could still be 'modified' from some other reference that is modifiable. Also as its just a readonly view of annother collection , When the source collection changes unModifiable Collection will always present with latest values.

However immutable Collection can be treated as a readonly copy of another collection and can not be modified. In this case when the source collection changes , immutable Collection do not reflect the changes

Here is a testcase to visualise this difference.

@Test
public void testList() {

	List<String> modifiableList = new ArrayList<String>();
	modifiableList.add("a");
	
	System.out.println("modifiableList:"+modifiableList);
	System.out.println("--");


	//unModifiableList

	assertEquals(1, modifiableList.size());
	
	List<String> unModifiableList=Collections.unmodifiableList(
										modifiableList);
	
	modifiableList.add("b");
	
	boolean exceptionThrown=false;
	try {
		unModifiableList.add("b");
		fail("add supported for unModifiableList!!");
	} catch (UnsupportedOperationException e) {
		exceptionThrown=true;
		System.out.println("unModifiableList.add() not supported");
	}
	assertTrue(exceptionThrown);
	
	System.out.println("modifiableList:"+modifiableList);
	System.out.println("unModifiableList:"+unModifiableList);
	
	assertEquals(2, modifiableList.size());
	assertEquals(2, unModifiableList.size());
            System.out.println("--");
	


            //immutableList

	
	List<String> immutableList=Collections.unmodifiableList(
							new ArrayList<String>(modifiableList));
	
	modifiableList.add("c");

	exceptionThrown=false;
	try {
		immutableList.add("c");
		fail("add supported for immutableList!!");
	} catch (UnsupportedOperationException e) {
		exceptionThrown=true;
		System.out.println("immutableList.add() not supported");
	}
	assertTrue(exceptionThrown);
	
	
	System.out.println("modifiableList:"+modifiableList);
	System.out.println("unModifiableList:"+unModifiableList);
	System.out.println("immutableList:"+immutableList);
	System.out.println("--");

	assertEquals(3, modifiableList.size());
	assertEquals(3, unModifiableList.size());
	assertEquals(2, immutableList.size());

}

Output

modifiableList:[a]
--
unModifiableList.add() not supported
modifiableList:[a, b]
unModifiableList:[a, b]
--
immutableList.add() not supported
modifiableList:[a, b, c]
unModifiableList:[a, b, c]
immutableList:[a, b]
--

Solution 3 - Java

I think the main difference is that the owner of a mutable collection might want to provide access to the collection to some other code, but provide that access through an interface that doens't allow the other code to modify the collection (while reserving that capability to the owning code). So the collection isn't immutable, but certain users aren't permitted to change the collection.

Oracle's Java Collection Wrapper tutorial has this to say (emphasis added):

> Unmodifiable wrappers have two main uses, as follows: > > - To make a collection immutable once it has been built. In this case, it's good practice not to maintain a reference to the backing > collection. This absolutely guarantees immutability. > - To allow certain clients read-only access to your data structures. You keep a reference to the backing collection but hand > out a reference to the wrapper. In this way, clients can look but not > modify, while you maintain full access.

Solution 4 - Java

If we are talking about JDK Unmodifiable* vs guava Immutable*, actually the difference is also in performance. Immutable collections can be both faster and more memory-efficient if they are not wrappers around regular collections (JDK implementations are wrappers). Citing the guava team:

The JDK provides Collections.unmodifiableXXX methods, but in our opinion, these can be

<...>

  • inefficient: the data structures still have all the overhead of mutable collections, including concurrent modification checks, extra space in hash tables, etc.

Solution 5 - Java

To quote The Java™ Tutorials:

> Unlike synchronization wrappers, which add functionality to the wrapped collection, the unmodifiable wrappers take functionality away. In particular, they take away the ability to modify the collection by intercepting all the operations that would modify the collection and throwing an UnsupportedOperationException. Unmodifiable wrappers have two main uses, as follows: > > * To make a collection immutable once it has been built. In this case, it's good practice not to maintain a reference to the backing collection. This absolutely guarantees immutability. > > * To allow certain clients read-only access to your data structures. You keep a reference to the backing collection but hand out a reference to the wrapper. In this way, clients can look but not modify, while you maintain full access.

(emphasis mine)

This really sums it up.

Solution 6 - Java

    // normal list
    List list1 = new ArrayList();
    list1.add(1);

    // unmodifiable list
    List list2 = Collections.unmodifiableList(list1);

    // immutable list
    List list3 = Collections.unmodifiableList(new ArrayList<>(list1));

    list1.add(2);
    list1.add(3);

    System.out.println(list1);
    System.out.println(list2);
    System.out.println(list3);

Output:

[1, 2, 3]
[1, 2, 3]
[1]

Solution 7 - Java

An object is considered immutable if its state cannot change after it is constructed. After you create an immutable instance of a collection, it holds the same data as long as a reference to it exists.

One advantage of an immutable collection is that it is automatically thread safe. Collections containing immutable objects are automatically thread safe after construction. After you create such a collection, you can hand it to multiple threads, and they will all see a consistent view.

However, an immutable collection of objects is not the same as a collection of immutable objects. If the contained elements are mutable, then this may cause the collection to behave inconsistently or make its contents to appear to change.

In simple words, if you add a little immutability to something mutable, you get mutability. And if you add a little mutability to something immutable, you get mutability.

Immutable and Unmodifiable Are Not the Same :

The immutable collections behave in the same way as the Collections.unmodifiable... wrappers. However, these collections are not wrappers — these are data structures implemented by classes where any attempt to modify the data causes an exception to be thrown.

If you create a List and pass it to the Collections.unmodifiableList method, then you get an unmodifiable view. The underlying list is still modifiable, and modifications to it are visible through the List that is returned, so it is not actually immutable.

To demonstrate this behavior, create a List and pass it to Collections.unmodifiableList. If you try to add to that unmodifiable List directly, then an UnsupportedOperationException is thrown.

But, if you change the original List, no error is generated, and the unmodifiable List has been modified.

In this case, to make a collection immutable once it has been built, it's a good practice not to maintain a reference to the backing collection. This absolutely guarantees immutability.

Further, to allow certain clients read-only access to your data structures. You can keep a reference to the backing collection but hand out a reference to the wrapper. In this way, clients can look but not be able to modify, while you maintain full access.

So, an immutable collection can contain mutable objects, and if it does, the collection is neither immutable nor thread safe.

Solution 8 - Java

As noted above unmodifiable is not like immutable because an unmodifiable collection can be altered if for example an unmodifiable collection has an underlying delegate collection which is referenced by some other object and that object changes it.

Regarding immutable, it's not even well defined. However, generally it means that the object "will not change", but that would need to be defined recursively. For example, I can define immutable on classes whose instance variables are all primitives and whose methods all contain no arguments and return primitives. The methods then recursively allow the instance variables to be immutable and all methods to contain arguments that are immutable and that return immutable values. The methods should be guaranteed to return the same value over time.

Assuming that we can do that, there is also the concept thread safe. And you might be led to believe that immutable (or not changeble over time) also implies thread safe. However that is not the case and that is the main point I am making here that has not yet been noted in other answers. I can construct an immutable object that always returns the same results yet is not thread safe. To see this suppose that I construct an immutable collection by maintaining additions and deletions over time. Now the immutable collection returns its elements by looking at the internal collection (which may be changing over time) and then (internally) adding and deleting the elements that were added or deleted after creation of the collection. Clearly, although the collection would always return the same elements, it is not thread safe merely because it will never change value.

Now we can define immutable as objects that are thread safe and will never change. There are guidelines for creating immutable classes that generally lead to such classes, however, keep in mind that there may be ways to create immutable classes, that require attention to thread safety, for example, as described in the "snapshot" collection example above.

Solution 9 - Java

The Java™ Tutorials say the following:

> Unlike synchronization wrappers, which add functionality to the > wrapped collection, the unmodifiable wrappers take functionality away. > In particular, they take away the ability to modify the collection by > intercepting all the operations that would modify the collection and > throwing an UnsupportedOperationException. Unmodifiable wrappers have > two main uses, as follows: > > To make a collection immutable once it has been built. In this case, > it's good practice not to maintain a reference to the backing > collection. This absolutely guarantees immutability. > > To allow certain clients read-only access to your data structures. You > keep a reference to the backing collection but hand out a reference to > the wrapper. In this way, clients can look but not modify, while you > maintain full access.

I think its a good enough explanation to understand the difference.

Solution 10 - Java

Unmodifiable vs Immutable Collection

Create A modifiable map

Map<String, String> modifiableMap = new HashMap();
modifiableMap.put(“1”,”one”);
modifiableMap.put(“2”,”two”);
modifiableMap.put(“3”,”three”);

Create an unmodifiableMap out of modifiableMap

 Map<String,String> unmodifiableMap = Collections.unmodifiableMap(modifiableMap);
    unmodifiableMap.put(“4”,”Four”)  ==>Exception
    modifiableMap.put(“4”,”Four”);   ==>Allowed, this will also reflect now in the unmodifiableMap , because unmodifiableMap() returns a wrapper around modifiableMap.
     

Create an immutableMap out of modifiableMap

 Map<String,String> immutableMap = Collections.immutableMap(modifiableMap);
    immutableMap.put(“5”,”Five”) ==>Exception
    modifiableMap.put(“5”,”Five”);   ==>Allowed, BUT this will NOT reflect now in the immutableMap, because immutableMap() returns a copy of the modifiableMap.

Solution 11 - Java

[Unmodifiable and Immutable]

Unmodifiable collection(object) can still be changed by changing origin object. It is possible using reference.

Java provides with several ways to create an Unmodifiable map:

  • Collections.unmodifiableMap()

  • Java 9 Map.of(), Map.ofEntries()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCratylusView Question on Stackoverflow
Solution 1 - JavaJon SkeetView Answer on Stackoverflow
Solution 2 - JavaPrashant BhateView Answer on Stackoverflow
Solution 3 - JavaMichael BurrView Answer on Stackoverflow
Solution 4 - JavaDmideView Answer on Stackoverflow
Solution 5 - JavaBharathView Answer on Stackoverflow
Solution 6 - Javauser3234777View Answer on Stackoverflow
Solution 7 - JavaAbhishek RajView Answer on Stackoverflow
Solution 8 - Javadan bView Answer on Stackoverflow
Solution 9 - Javapiyush121View Answer on Stackoverflow
Solution 10 - JavaTruckDriverView Answer on Stackoverflow
Solution 11 - JavayoAlex5View Answer on Stackoverflow