This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

Immutable Collections in Java

Description

<n>This article was originally published on the <a href="http://blogs.encodo.ch/news/view_article.php?id=6"><b>Encodo Blogs</b></a>. Browse on over to see more!</n> <hr> Java supports immutable collections of all kinds, but not in the way you would expect. A naive implementation would declare the immutable (<i>unmodifiable</i> in Java parlance) interface as follows<fn>: <code> <b>interface</b> UnmodifiableList<t> { <b>function</b> T get(); <b>function</b> int size(); } </code> There <i>is</i> no way to modify this list---the API is simply not available. That done, we can now create the modifiable version of the list as follows: <code> <b>interface</b> List<t> <b>extends</b> UnmodifiableList<t> { <b>function</b> void add(T); <b>function</b> remove(T); } </code> A class can now use these interfaces to carefully control access to a list as follows: <code> <b>class</b> SomeClass { <b>private</b> List<someotherclass> list; <b>function</b> UnmodifiableList<someotherclass> getList() { <b>return</b> list; } } </code> That would be pretty cool, right? Unfortunately, even if you declared these interfaces yourself, the example above does not work. Java's generics support amounts to little more than syntactic sugar, so List<someotherclass> does not conform to UnmodifiableList<someotherclass>. There are several solutions to this problem: <ul> Create a result list of the correct type and populate it with the elements of the private list Perform the typecast anyway, ignoring or suppressing the error. Since Java employs erasure to transform generics when compiled, both would compile down to Array<object> anyway.<fn> Declare a method in the <c>List</c> interface that returns it as an unmodifiable list. This is probably the best solution, as the code for unmodifiability will be defined in one place, the implementing collection. </ul> So that was fun, but how exactly does it work in Java, then? In addition to the limited generics, Java is further hampered by a legacy of old code. This means that they can't (read: won't) change existing interfaces because it might break existing code. Here's how Java defines the two interfaces: <code> <b>interface</b> List<t> { <b>function</b> T get(); <b>function</b> int size(); <b>function</b> void add(T); <b>function</b> remove(T); } </code> There <i>is</i> no second interface. All lists have methods for adding and removing elements---even immutable ones. Immutability is enforced at run-time, not compile-time. Pretty cool, huh? Not only that, but <c>List</c> itself doesn't even have a method to return an unmodifiable version of itself because Sun didn't want to add methods to existing interfaces. Instead, you use a static method on the <c>Collections</c> class to get an immutable version of a list. <code> <b>class</b> SomeClass { <b>private</b> List<someotherclass> list; <span style="color: green">/** * Returns an unmodifiable list (treat as read-only). */</span> <b>function</b> List<someotherclass> getList() { <b>return</b> Collections.unmodifiableList(list); } } </code> The type system itself has nothing to say about modifiability. Any calling client can happily add elements to and remove elements from the result without any inkling that what they are doing is wrong. The compiler certainly won't tell them; the Javadoc offers the only clue---in effect supplementing the type systems with <i>comments</i>! When that code is called at run-time, Java will happily issue an <c>UnsupportedOperationException</c> and smile smugly to itself for a job well done. Say it with me: <b>backwards-compatibility is king!</b> <hr> <ft>I know this won't compile; it's Java-esque pseudo code to illustrate the idea.</ft> <ft>I'm not sure exactly which container class Java employs during erasure, so I'm using <c>Array</c> as a placeholder here.</ft>