The Java Collection framework provides an elegant solution to create an unmodifiable Collection like Lists,Sets,Maps from an existing one.Sounds too good.Will it server our purpose?One day was debugging an issue about mutable objects and unmodifiable list.Got a very peculiar behavior.
Lets consider below code snippet.
.
public class UnmodifibleList {
public static void main(String[] args) {
String s1= "Good";
String s2= "Morning";
final List modifiableList = new ArrayList();
modifiableList.add(s1);
modifiableList.add(s2);
final List unmodifiableList = Collections.unmodifiableList(modifiableList);
System.out.println("Before modifying: " + unmodifiableList );
modifiableList .add("nice");
modifiableList .add("day");
System.out.println("After modifying: " + unmodifiableList);
}
}
And the Output as follows:
Before modifying: [Good, Morning]
After modifying: [Good, Morning, nice, day]
Is it seems strange? Unmodifiable list gets modified after the method call Collections.unmodifiableList()
What the java doc says:
Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
The returned list will be serializable if the specified list is serializable. Similarly, the returned list will implement
public static void main(String[] args) {
String s1= "Good";
String s2= "Morning";
final List modifiableList = new ArrayList();
modifiableList.add(s1);
modifiableList.add(s2);
final List unmodifiableList = Collections.unmodifiableList(new ArrayList(modifiableList));
System.out.println("Before modifying: " + unmodifiableList );
modifiableList .add("nice");
modifiableList .add("day");
System.out.println("After modifying: " + unmodifiableList);
}
}
Please look at the line in the above code where we are calling
Collections.unmodifiableList().Here we are creating a brand new ArrayList and passing the original list inside it.
And the Output as follows:
Before modifying: [Good, Morning]
After modifying: [Good, Morning]
Mutable Object and unmodifiable Collection:
Suppose We have a mutable object and our collection will contain the mutable objects.Please follow the below code snippets to get the better understanding.
public class UnmodifibleMutableList {
public static void main(String[] args) {
StringBuffer s1= new StringBuffer("Good");
StringBuffer s2= new StringBuffer("Morning");
final List modifiableList = new ArrayList();
modifiableList.add(s1);
modifiableList.add(s2);
final List unmodifiableList = Collections.unmodifiableList(modifiableList);
System.out.println("Before modification: " + unmodifiableList );
s1.replace(0, 3, "ba");
System.out.println("After modification: " + unmodifiableList);}
}
Here notice that StringBuffer is a mutable class .After calling Collections.unmodifiableList();
we are doing some manipulation with the StringBuffer s1.And that will be reflected in unmodifiable list.
And the Output as follows:
Before modification: [Good, Morning]
After modification: [bad, Morning]
We have to be conscious that if we modify any of the objects within any of the lists, then all the lists containing the same object will observe the modification.But this is not the case in case of String.As String is immutable and thus cannot be changed once created.
Lets consider below code snippet.
.
public class UnmodifibleList {
public static void main(String[] args) {
String s1= "Good";
String s2= "Morning";
final List
modifiableList.add(s1);
modifiableList.add(s2);
final List
System.out.println("Before modifying: " + unmodifiableList );
modifiableList .add("nice");
modifiableList .add("day");
System.out.println("After modifying: " + unmodifiableList);
}
}
And the Output as follows:
Before modifying: [Good, Morning]
After modifying: [Good, Morning, nice, day]
Is it seems strange? Unmodifiable list gets modified after the method call Collections.unmodifiableList()
What the java doc says:
Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
The returned list will be serializable if the specified list is serializable. Similarly, the returned list will implement
RandomAccess
if the specified list does.
- Parameters:
- list the list for which an unmodifiable view is to be returned.
- Returns:
- an unmodifiable view of the specified list.
- But it does not say if we modify the underlying collection the returned unmodifiable list will also be modified.
- Steps to avoid this:
public static void main(String[] args) {
String s1= "Good";
String s2= "Morning";
final List
modifiableList.add(s1);
modifiableList.add(s2);
final List
System.out.println("Before modifying: " + unmodifiableList );
modifiableList .add("nice");
modifiableList .add("day");
System.out.println("After modifying: " + unmodifiableList);
}
}
Please look at the line in the above code where we are calling
Collections.unmodifiableList().Here we are creating a brand new ArrayList and passing the original list inside it.
And the Output as follows:
Before modifying: [Good, Morning]
After modifying: [Good, Morning]
Mutable Object and unmodifiable Collection:
Suppose We have a mutable object and our collection will contain the mutable objects.Please follow the below code snippets to get the better understanding.
public class UnmodifibleMutableList {
public static void main(String[] args) {
StringBuffer s1= new StringBuffer("Good");
StringBuffer s2= new StringBuffer("Morning");
final List
modifiableList.add(s1);
modifiableList.add(s2);
final List
System.out.println("Before modification: " + unmodifiableList );
s1.replace(0, 3, "ba");
System.out.println("After modification: " + unmodifiableList);}
}
Here notice that StringBuffer is a mutable class .After calling Collections.unmodifiableList();
we are doing some manipulation with the StringBuffer s1.And that will be reflected in unmodifiable list.
And the Output as follows:
Before modification: [Good, Morning]
After modification: [bad, Morning]
We have to be conscious that if we modify any of the objects within any of the lists, then all the lists containing the same object will observe the modification.But this is not the case in case of String.As String is immutable and thus cannot be changed once created.