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.
[an error occurred while processing this directive]
|
|