What's Wrong With Java Collections?

With the release of Java version 1.2 came the addition of a standard way to deal with groupings of objects. In earlier versions, we had Vectors, Stacks, Dictionaries, and Hashtables. This was a pretty limited and somewhat weak means for handling these groupings of objects. With version 1.2 that all changed as this idea of "Collections" came about.

From its inception, I was drawn to Java by this idea that everything extends from Object, therefore everything is an Object (with the exception of primitives, of course). To me, this is what makes an Object-Oriented language... everything is an Object.

Add a little tequila...     
...to your Java

... Anyway, back to this "Collections" thing. So 1.2 introduced The Collections Framework (Tutorial). I, as did many Java Developers, applauded and welcomed this new addition to our Java world. This Framework would go miles to standardize how us developers would manage the transmission and consumption of groupings of objects within our code. As Object was the base for everything in Java 1.0, in Java 1.2, all of these "object groupings" had a base called java.util.Collection (well almost all, Map is the key variant on this pattern, but that's outside the scope of this discussion). Unlike Object, this java.util.Collection thing isn't an object, rather it is an interface shared and implemented by all collection implementations. This is a key point to grasp, as the premise for my discussion hinges directly on this fact, but I'll get to that later.

What's Right with Collections

The java.util.Collection interface keys on the fact that everything in Java is an Object. It utilizes this assumption heavily, in that all implementations of the interface provide operations to manipulate collections of Objects. Along with the collection interface, we were also given some very good subinterfaces, such as Set and List, and a good traversal interface called Iterator. Set and List are both Collections, but the two key differentiators between Set and List is that a Set is unordered where a List is ordered, and a Set contains only unique elements whereas a List can contain duplicates. And Iterator, gives us a nice universal interface for (as the name implies) iterating over a collection and manipulating the objects contained in that collection.

Wow! Those Java folks thought of everything! Or did they? Well what if, in my code, I want to share my Collection (either by my code invoking an external method, or by my code returning a Collection to be used by some external code) with an external piece of code, but without allowing that external code the ability to modify my precious collection? Yep, those nice Java folks even thought of that! They were kind enough to provide us with some convenience methods in java.util.Collections (yes, that's right... plural, as in with an "s") to allow us to create immutable (Definition) collections that we could then pass around and not fear the wrath of what might happen should our precious collection be modified. For example, java.util.Collections provides an unmodifiableCollection() method that takes a presumably modifiable collection and returns one whose contents are structurally identical, but cannot be modified.

Not only were convenience methods provided, but some of the internal 1.2 API made use of immutable collections, and would return immutable collections at seemingly random times. Well, ok, so it wasn't exactly random, and the times that immutable collections were returned were done so for good reason. However, either I failed to read the documentation (in some cases), or I failed to grasp the importance of the returned collection being immutable (also some cases), or the documentation just didn't do a good job of telling me when the collection being returned was immutable (also in some cases). And this caused me many many headaches. So why was this new, wonderful Collection Framework, torturing me so? Welcome to Pointville, the whole reason for this discussion...

This may seem relatively trivial to some, and minor to others, and it may just sound like I'm being nitpicky, but the java.util.Collection interface is broken. You heard (read) me right, B.R.O.K.E.N. BROKEN! Those Java folks went all that way to provide us developers with such an elegant solution to universally manage groupings of objects, but they came up just short. Apparently someone over there fell asleep the day they taught the concept of contracts in OO class. See, in OO there is this concept known as contracts which basically states that if I provide you an Object with a well-defined contract, you are safe to use that Object within the bounds of that contract without worry that my Object is going to violate that contract. From the very beginning, Java chose to encapsulate this concept of contracts in a little thing called an interface. So, in Java, when an Object implements an interface, it agrees to be bound by the "contract" defined by that interface.

What's Wrong with Collections

So why is java.util.Collection broken? Because, java.util.Collection (which is a Java interface) and it's immutable concrete implementations do not adhere to this principle. According to the javadocs for java.util.Collection, all six of the methods that provide mutable behavior (add, addAll, clear, remove, removeAll, and retainAll) are labelled, and I quote, "optional operation", and will throw an "UnsupportedOperationException" should the concrete implementation so choose. "[O]ptional operation"? Are you friggin kidding me? What a wonderful new pattern! I think I'll start using it in my code. I think I'll start adding methods to all of my classes such as "endWorldHunger()" and "cureCancer()", and in my javadocs, I'll label them as "optional operation" and in my implementation I'll just throw "UnsupportedOperationException". And when my employer asks me to implement a financial system, I'll provide a class with a method called "doSomeFinancialCalculation()", and my javadocs will state that this is an "optional operation" and my implementation will just throw "UnsupportedOperationException". Yeah, I wonder how long this will keep me employed. Me, to my boss, "But sir, I wrote a class...".

How it Should Have Been Done

Note the words "should have". It's far too late to fix this now... millions of lines of code have already been written, retrofitting now would be costly and burdonsome. But, as they say, hindsight is 20/20. So how should this have been done. Had our Java friends just taken an extra 15 minutes when the Collection Framework was developed, all of this could have been avoided. Had the current Collection interface had been assumed to be immutable and left out those six methods listed above, all we'd have had to do is add a subinterface called "ModifiableCollection" or "MutableCollection" that then adds those six methods. Then anyplace we want an immutable collection, we use Collection, and anyplace we need the ability to modify a collection, we use a "MutableCollection". Oh how simple this could have been... Had this been done from the get-go, us developers could have avoided the headaches that this has caused, and the Java folks could have looked back at the Java Collections Framework as a pinnacle of success, a story to be passed on to new generations. Ok, ok, I'm being a bit melodrammatic here, but the point remains... Collections were oh so close to being perfect.

Reader Comments:

10/09/2012 5:04 AM - Elyza wrote:
I'm not easily impesrsed. . . but that's impressing me! :)

05/18/2011 10:39 PM - glenviewjeff wrote:
I just started looking at the interface for Collection and was also surprised by its seemingly poor design. That's what prompted me to do a web search for "what's wrong with java, unsupportedoperationexception" which brought me here! I completely agree with you regarding the simple design change they could have made. So, is there any drawback to creating and using our own interface called ImmutableCollection that omits the mutating methods?

Post a Comment:

Your Name:
Your Comment:

 Last Updated: Tuesday June 10, 2014