This was considered and rejected, because it would have led to too many interfaces and classes in the Collections hierarchy :
Why don't you support immutability directly in the core collection
interfaces so that you can do away with optional operations (and
UnsupportedOperationException)?
This is the most controversial design decision in the whole API.
Clearly, static (compile time) type checking is highly desirable, and
is the norm in Java. We would have supported it if we believed it were
feasible. Unfortunately, attempts to achieve this goal cause an
explosion in the size of the interface hierarchy, and do not succeed
in eliminating the need for runtime exceptions (though they reduce it
substantially).
Doug Lea, who wrote a popular Java collections package that did
reflect mutability distinctions in its interface hierarchy, no longer
believes it is a viable approach, based on user experience with his
collections package. In his words (from personal correspondence) "Much
as it pains me to say it, strong static typing does not work for
collection interfaces in Java."
To illustrate the problem in gory detail, suppose you want to add the
notion of modifiability to the Hierarchy. You need four new
interfaces: ModifiableCollection, ModifiableSet, ModifiableList, and
ModifiableMap. What was previously a simple hierarchy is now a messy
heterarchy. Also, you need a new Iterator interface for use with
unmodifiable Collections, that does not contain the remove operation.
Now can you do away with UnsupportedOperationException? Unfortunately
not.
Consider arrays. They implement most of the List operations, but not
remove and add. They are "fixed-size" Lists. If you want to capture
this notion in the hierarchy, you have to add two new interfaces:
VariableSizeList and VariableSizeMap. You don't have to add
VariableSizeCollection and VariableSizeSet, because they'd be
identical to ModifiableCollection and ModifiableSet, but you might
choose to add them anyway for consistency's sake. Also, you need a new
variety of ListIterator that doesn't support the add and remove
operations, to go along with unmodifiable List. Now we're up to ten or
twelve interfaces, plus two new Iterator interfaces, instead of our
original four. Are we done? No.
Consider logs (such as error logs, audit logs and journals for
recoverable data objects). They are natural append-only sequences,
that support all of the List operations except for remove and set
(replace). They require a new core interface, and a new iterator.
And what about immutable Collections, as opposed to unmodifiable ones?
(i.e., Collections that cannot be changed by the client AND will never
change for any other reason). Many argue that this is the most
important distinction of all, because it allows multiple threads to
access a collection concurrently without the need for synchronization.
Adding this support to the type hierarchy requires four more
interfaces.
Now we're up to twenty or so interfaces and five iterators, and it's
almost certain that there are still collections arising in practice
that don't fit cleanly into any of the interfaces. For example, the
collection-views returned by Map are natural delete-only collections.
Also, there are collections that will reject certain elements on the
basis of their value, so we still haven't done away with runtime
exceptions.
When all was said and done, we felt that it was a sound engineering
compromise to sidestep the whole issue by providing a very small set
of core interfaces that can throw a runtime exception.