I have been using guava for some time now and truly trusted it, until I stumbled of an example yesterday, which got me thinking. Long story short, here it is:
public static void testGuavaImmutability(){
StringBuilder stringBuilder = new StringBuilder("partOne");
ImmutableList<StringBuilder> myList = ImmutableList.of(stringBuilder);
System.out.println(myList.get(0));
stringBuilder.append("appended");
System.out.println(myList.get(0));
}
After running this you can see that the value of an entry inside an ImmutableList has changed. If two threads were involved here, one could happen to not see the updated of the other.
Also the thing that makes me very impatient for an answer is that Item15 in Effective Java, point five says this:
Make defensives copies in the constructor - which seems pretty logic.
Looking at the source code of the ImmutableList, I see this:
SingletonImmutableList(E element) {
this.element = checkNotNull(element);
}
So, no copy is actually made, although I have no idea how a generic deep copy would be implemented in such a case (may be serialization?).
So.. why are they called Immutable then?
What you're getting at here is the difference between immutable and deeply immutable.
An immutable object will never change, but anything that it refers to might change. Deep immutability is much stronger: neither the base object nor any object you can navigate to from it will change.
Each is appropriate in its own situations. When you create your own class that has a field of type Date, that date is owned by your object; it's truly a part of it. Therefore, you should make defensive copies of it (on the way in and the way out!) to provide deep immutability.
But a collection does not really "own" its elements. Their states are not considered part of the collection's state; it is a different type of class -- a container. (Furthermore, as you allude, it has no deep knowledge of what element type is being used, so it wouldn't know how to copy the elements anyway.)
Another answer states that the Guava collections should have used the term unmodifiable. But there is a very well-defined difference between the terms unmodifiable and immutable in the context of collections, and it has nothing to do with shallow vs. deep immutability. "Unmodifiable" says you cannot change this instance, via the reference you have; "immutable" means this instance cannot change, period, whether by you or any other actor.
The list itself is immutable because you cannot add/remove elements. The elements are on their own regarding immutability. In more precise terms, we have definitions from a historical Java 1.4.2 document:
Collections that do not support any modification operations (such as add, remove and clear) are referred to as unmodifiable. Collections that are not unmodifiable are referred to modifiable.
Collections that additionally guarantee that no change in the Collection object will ever be visible are referred to as immutable. Collections that are not immutable are referred to as mutable.
Note that for these definitions to make any sense we must assume an implicit distiction between a collection in an abstract sense and an object that represents that collection. This is important because the object that represents an immutable collection is not itself immutable by any standard definition of that term. For example, its equals relation has no temporal consistency, a vital requirement on immutable objects.
As far as defensive copying, note that is an ill-defined problem in general and there will never be a general immutable collection in Java that will manage to defensively copy its elements. Note additionally that such a collection would be less useful than the immutable collections that really exist: when you put an object into a collection, in 99.99% cases you want that very object to be there, not some other object that is not even equal to it.
There is a quite standard definition of object immutability (as opposed to collection immutability) which assumes transitive immutability of the whole object graph reachable from the immutable object. Taken too literally, though, such a definition will almost never be satisfied in the real world. Two cases in point:
nothing is immutable in the face of reflection. Even final fields are writable.
even String, that bastillon of immutability, has been proven mutable outside the Java sandbox (without a SecurityManager—which covers 99% of real-world Java programs).
You mix the immutability of the list and the immutability of the objects it contains.
In an immutable collection you cannot add/remove objects, but if the object it contains are mutable you can modify them after get()ing them.
Related
The list returned by the method List.of(E... elements) in java does return an immutable list, but this is not visible at all by looking at the created list. The created list simply throws an Exception instead of not showing the possiblity to change the list at all.
My point is, that List.of(E... elements) should return a ImmutableList that extends List. This way the user can decide if he cares to show this fact of immutability or not.
But I don't find anybody complaining or showing alternative solutions. Even Guava and Apache Commons don't do this by default. Only Guava gives the possibilty to create it (albeit with a lot of code):
List<String> list = new ArrayList<String>(Arrays.asList("one", "two", "three"));
ImmutableList<String> unmodifiableList = ImmutableList.<String>builder().addAll(list).build();
But even this class has a (deprecated) add and remove method.
Can anyone tell me why nobody cares about this (seemingly fundamental) issue?
It's not that nobody cares; it's that this is a problem of considerable subtlety.
The original reason there isn't a family of "immutable" collection interfaces is because of a concern about interface proliferation. There could potentially be interfaces not only for immutability, but synchronized and runtime type-checked collections, and also collections that can have elements set but not added or removed (e.g., Arrays.asList) or collections from which elements can be removed but not added (e.g., Map.keySet).
But it could also be argued that immutability is so important that it should be special-cased, and that there be support in the type hierarchy for it even if there isn't support for all those other characteristics. Fair enough.
The initial suggestion is to have an ImmutableList interface extend List, as
ImmutableList <: List <: Collection
(Where <: means "is a subtype of".)
This can certainly be done, but then ImmutableList would inherit all of the methods from List, including all the mutator methods. Something would have to be done with them; a sub-interface can't "disinherit" methods from a super-interface. The best that could be done is to specify that these methods throw an exception, provide default implementations that do so, and perhaps mark the methods as deprecated so that programmers get a warning at compile time.
This works, but it doesn't help much. An implementation of such an interface cannot be guaranteed to be immutable at all. A malicious or buggy implementation could override the mutator methods, or it could simply add more methods that mutate the state. Any programs that used ImmutableList couldn't make any assumptions that the list was, in fact, immutable.
A variation on this is to make ImmutableList be a class instead of an interface, to define its mutator methods to throw exceptions, to make them final, and to provide no public constructors, in order to restrict implementations. In fact, this is exactly what Guava's ImmutableList has done. If you trust the Guava developers (I think they're pretty reputable) then if you have a Guava ImmutableList instance, you're assured that it is in fact immutable. For example, you could store it in a field with the knowledge that it won't change out from under you unexpectedly. But this also means that you can't add another ImmutableList implementation, at least not without modifying Guava.
A problem that isn't solved by this approach is the "scrubbing" of immutability by upcasting. A lot of existing APIs define methods with parameters of type Collection or Iterable. If you were to pass an ImmutableList to such a method, it would lose the type information indicating that the list is immutable. To benefit from this, you'd have to add immutable-flavored overloads everywhere. Or, you could add instanceof checks everywhere. Both are pretty messy.
(Note that the JDK's List.copyOf sidesteps this problem. Even though there are no immutable types, it checks the implementation before making a copy, and avoids making copies unnecessarily. Thus, callers can use List.copyOf to make defensive copies with impunity.)
As an alternative, one might argue that we don't want ImmutableList to be a sub-interface of List, we want it to be a super-interface:
List <: ImmutableList
This way, instead of ImmutableList having to specify that all those mutator methods throw exceptions, they wouldn't be present in the interface at all. This is nice, except that this model is completely wrong. Since ArrayList is a List, that means ArrayList is also an ImmutableList, which is clearly nonsensical. The problem is that "immutable" implies a restriction on subtypes, which can't be done in an inheritance hierarchy. Instead, it would need to be renamed to allow capabilities to be added as one goes down the hierarchy, for example,
List <: ReadableList
which is more accurate. However, ReadableList is altogether a different thing from an ImmutableList.
Finally, there are a bunch of semantic issues that we haven't considered. One concerns immutability vs. unmodifiability. Java has APIs that support unmodifiability, for example:
List<String> alist = new ArrayList<>(...);
??? ulist = Collections.unmodifiableList(alist);
What should the type of ulist be? It's not immutable, since it will change if somebody changes the backing list alist. Now consider:
???<String[]> arlist = List.of(new String[] { ... }, new String[] { ... });
What should the type be? It's certainly not immutable, as it contains arrays, and arrays are always mutable. Thus it's not at all clear that it would be reasonable to say that List.of returns something immutable.
Removing add, remove, etc. from all the Collection types and creating subinterfaces MutableCollection, MutableList, MutableSet would double the number of Collection interfaces, which is a complexity cost to be considered. Furthermore, Collections aren't cleanly separated into Mutable and Immutable: Arrays.asList supports set, but not add.
Ultimately there's a tradeoff to be made about how much to capture in the type system and how much to enforce at runtime. Reasonable people can disagree as to where to draw the line.
I would say that since commonly collections tend to (or at least should) be treated as "immutable by default" (meaning you're rarely modifying collections that you didn't create), it's not very important to specify that "this is immutable". It would be more useful to specify "you can safely modify this collection if you wish".
Secondly, your suggested approach wouldn't work. You can't extend List and hide methods, so the only option would be to make it return an ImmutableList that's not a subtype of List. That would make it useless, as it would require a new ImmutableList interface, and any existing code wouldn't be able to use it.
So is this optimal design? No, not really, but for backwards compatibility that's not going to change.
I downloaded the source code for Google Guava just out of curiosity to see what is backing the immutable collections.
I was going through the ImmutableList and I noticed that it was still backed by an old-fashioned array, as in Object[]
So I'm just curious, the Object[] array is probably mutable by its nature, and it is not threadsafe. I already knew that ArrayList and CopyOnWriteArrayList were backed by an Object[] array, but they are mutable.
So is the ImmutableList only immutable and threadsafe because its internal properties are well encapsulated and protected? Is it also immutable and threadsafe because the encapsulation ensures nothing will modify it after construction? Will there ever be a day where low-level arrays like this will be switched out for something better and not of a legacy, and be inherently immutable and final rather than immutable by careful encapsulation?
Yes, the ImmutableList is "only" immutable because it does not allow its internal backing array to be modified.
That is exactly the same situation as for a java.lang.String, which also wraps a private char[]. Along the same lines, the very useful concurrency libraries are largely implemented as regular Java classes relying on only very few (and very basic) JVM synchronization primitives.
So that should be good enough. Obviously, people writing these library classes have to be careful and knowledgable, but this requirement does not magically go away by moving the code even more "low-level" into JVM primitives. (Agreed, you can shoot yourself in the foot using dark voodoo like reflection now, but that hardly happens by accident, and in regular usage, a "user-land" implementation works just as well).
Will there ever be a day
That is pure speculation. But there is apparently work on "value types", which is a related topic.
This question already has answers here:
Java Immutable Collections
(7 answers)
Closed 9 months ago.
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?
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.
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]
--
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.
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.
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.
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.
// 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]
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.
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.
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.
[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()
It is obvious that immutability increases the re-usability since it creates new object in each state change.Can somebody tells me a practical scenario where we need a immutable class ?
Consider java.lang.String. If it weren't immutable, every time you ever have a string you want to be confident wouldn't change underneath you, you'd have to create a copy.
Another example is collections: it's nice to be able to accept or return a genuinely immutable collection (e.g. from Guava - not just an immutable view on a mutable collection) and have confidence that it won't be changed.
Whether those count as "needs" or not, I don't know - but I wouldn't want to develop without them.
A good example is related to hashing. A class overrides the equals() and hashCode() methods so that it can be used in data structures like HashSet and (as keys in) HashMap, and the hash code is typically derived by some identifying member attributes. However, if these attributes were to change then so would the object's hash code, so the object is no longer usable in a hashing data structure.
Java provides a nice example: String.
This article has a good color example (since color definitions don't change).
http://www.ibm.com/developerworks/java/library/j-jtp02183/index.html
The possible answers are either "never" or "it depends".
Personally, I would say, it depends.
Following usage would make a collection appear (to me) to be a flyweight:
public final static List<Integer> SOME_LIST =
Collections.unmodifiableList(
new LinkedList<Integer>(){ // scope begins
{
add(1);
add(2);
add(3);
}
} // scope ends
);
Right? You can't ever change it, because the only place where the
"original" collection object is known (which could be changed), is the
scope inside unmodifiableList's parameter list, which ends immediately.
Second thing is: when you retrieve an element from the list, it's an
Integer which itself is a flyweight.
Other obvious cases where final static and unmodifiableList are
not used, would not be considered as flyweights.
Did I miss something?
Do I have to consider some internal aspects of LinkedList which could
compromise the flyweight?
i think you are referring to the flyweight pattern. the fundamental idea of this pattern is that you are dealing with complex objects whose instances can be reused, and put out different representations with its methods.
to make such a object work correctly it should be immutable.
immutability is clearly given when creating a List the way you described.
but since there is no external object/parameters on which the SOME_LISt operates on i would not call this an example of a flyweight pattern.
another typical property of the flyweight pattern is the "interning" of such objects. when creating just a single instance of an object this does not make sense.
if you are dealing a lot with lists that are passed around from one object to another and you want to ensure the Immutability, a better option might be to use Google-Collections.
final static ImmutableList<Integer> someList = ImmutableList.of(1, 2, 3);
of course it is also possible to construct more complex Immutable Objects with Builders.
this creates an instance of an immutable list. it will still implement the List interface, but will refuse to execute any add(),addAll() set(), remove() operation.
so you can still pass it to methods when a List interface is required, yet be sure that its content is not altered.
I think your example are for immutable objects, a flyweight is something quite different. Immutable objects are candidates for flyweight, but a flyweight doesn't have to be immutable, it just has to be designed to save memory.
Having the library detect that the mutable List has not otherwise escaped is a bit of an ask, although theoretically possible.
If you serialise the returned object, then trusted code could view the internal object. Although the serialised form of the class are documented, it's not documented that the method uses those classes.
In practical terms, any cache is down to the user of the API.
(Why LinkedList for an immutable list, btw? Other than it changes the unmodifiable implementation.)
Integer is only a flyweight from -128 to 127.
See also http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-designpatterns.html.