396 lines
19 KiB
HTML
396 lines
19 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
This code is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License version 2 only, as
|
|
published by the Free Software Foundation. Oracle designates this
|
|
particular file as subject to the "Classpath" exception as provided
|
|
by Oracle in the LICENSE file that accompanied this code.
|
|
|
|
This code is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
version 2 for more details (a copy is included in the LICENSE file that
|
|
accompanied this code).
|
|
|
|
You should have received a copy of the GNU General Public License version
|
|
2 along with this work; if not, write to the Free Software Foundation,
|
|
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
or visit www.oracle.com if you need additional information or have any
|
|
questions.
|
|
-->
|
|
<html lang="en-US">
|
|
<head>
|
|
<title>Java Collections API Design FAQ</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
</head>
|
|
<body>
|
|
<h1>Java Collections API Design FAQ</h1>
|
|
<!-- Body text begins here -->
|
|
<hr>
|
|
This document answers frequently asked questions concerning the
|
|
design of the Java collections framework. It is derived from the
|
|
large volume of traffic on the collections-comments alias. It
|
|
serves as a design rationale for the collections framework.
|
|
<h2>Core Interfaces - General Questions</h2>
|
|
<ol>
|
|
<li><a href="#a1"><b>Why don't you support immutability directly in
|
|
the core collection interfaces so that you can do away with
|
|
<em>optional operations</em> (and
|
|
UnsupportedOperationException)?</b></a></li>
|
|
<li><a href="#a2"><b>Won't programmers have to surround any code
|
|
that calls optional operations with a try-catch clause in case they
|
|
throw an UnsupportedOperationException?</b></a></li>
|
|
<li><a href="#a3"><b>Why isn't there a core interface for "bags"
|
|
(AKA multisets)?</b></a></li>
|
|
<li><a href="#a28"><b>Why didn't you use "Beans-style names" for
|
|
consistency?</b></a></li>
|
|
</ol>
|
|
<h2>Collection Interface</h2>
|
|
<ol>
|
|
<li><a href="#a5"><b>Why doesn't Collection extend Cloneable and
|
|
Serializable?</b></a></li>
|
|
<li><a href="#a6"><b>Why don't you provide an "apply" method in
|
|
Collection to apply a given method ("upcall") to all the elements
|
|
of the Collection?</b></a></li>
|
|
<li><a href="#a7"><b>Why didn't you provide a "Predicate" interface,
|
|
and related methods (e.g., a method to find the first element in
|
|
the Collection satisfying the predicate)?</b></a></li>
|
|
<li><a href="#a8"><b>Why don't you provide a form of the addAll
|
|
method that takes an Enumeration (or an Iterator)?</b></a></li>
|
|
<li><a href="#a9"><b>Why don't the concrete implementations in the
|
|
JDK have Enumeration (or Iterator) constructors?</b></a></li>
|
|
<li><a href="#a10"><b>Why don't you provide an Iterator.add
|
|
method?</b></a></li>
|
|
</ol>
|
|
<h2>List Interface</h2>
|
|
<ol>
|
|
<li><a href="#a11"><b>Why don't you rename the List interface to
|
|
Sequence; doesn't "list" generally suggest "linked list"? Also,
|
|
doesn't it conflict with java.awt.List?</b></a></li>
|
|
<li><a href="#a12"><b>Why don't you rename List's set method to
|
|
replace, to avoid confusion with Set.</b></a></li>
|
|
</ol>
|
|
<h2>Map Interface</h2>
|
|
<ol>
|
|
<li><a href="#a14"><b>Why doesn't Map extend
|
|
Collection?</b></a></li>
|
|
</ol>
|
|
<h2>Iterator Interface</h2>
|
|
<ol>
|
|
<li><a href="#a18"><b>Why doesn't Iterator extend
|
|
Enumeration?</b></a></li>
|
|
<li><a href="#a19"><b>Why don't you provide an Iterator.peek method
|
|
that allows you to look at the next element in an iteration without
|
|
advancing the iterator?</b></a></li>
|
|
</ol>
|
|
<h2>Miscellaneous</h2>
|
|
<ol>
|
|
<li><a href="#a23"><b>Why did you write a new collections framework
|
|
instead of adopting JGL (a preexisting collections package from
|
|
ObjectSpace, Inc.) into the JDK?</b></a></li>
|
|
<li><a href="#a26"><b>Why don't you eliminate all of the methods and
|
|
classes that return "views" (Collections backed by other
|
|
collection-like objects). This would greatly reduce
|
|
aliasing.</b></a></li>
|
|
<li><a href="#a27"><b>Why don't you provide for "observable"
|
|
collections that send out Events when they're
|
|
modified?</b></a></li>
|
|
</ol>
|
|
<hr>
|
|
<h2>Core Interfaces - General Questions</h2>
|
|
<ol>
|
|
<li><a id="a1"><b>Why don't you support immutability
|
|
directly in the core collection interfaces so that you can do away
|
|
with <em>optional operations</em> (and
|
|
UnsupportedOperationException)?</b></a>
|
|
<p>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).</p>
|
|
<p>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."</p>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<p>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 <em>collection-views</em> 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.</p>
|
|
<p>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.</p>
|
|
</li>
|
|
<li><a id="a2"><b>Won't programmers have to surround any
|
|
code that calls optional operations with a try-catch clause in case
|
|
they throw an UnsupportedOperationException?</b></a>
|
|
<p>It was never our intention that programs should catch these
|
|
exceptions: that's why they're unchecked (runtime) exceptions. They
|
|
should only arise as a result of programming errors, in which case,
|
|
your program will halt due to the uncaught exception.</p>
|
|
</li>
|
|
<li><a id="a3"><b>Why isn't there a core interface for
|
|
"bags" (AKA multisets)?</b></a>
|
|
<p>The Collection interface provides this functionality. We are not
|
|
providing any public implementations of this interface, as we think
|
|
that it wouldn't be used frequently enough to "pull its weight." We
|
|
occasionally return such Collections, which are implemented easily
|
|
atop AbstractCollection (for example, the Collection returned by
|
|
Map.values).</p>
|
|
</li>
|
|
<li><a id="a28"><b>Why didn't you use "Beans-style
|
|
names" for consistency?</b></a>
|
|
<p>While the names of the new collections methods do not adhere to
|
|
the "Beans naming conventions", we believe that they are
|
|
reasonable, consistent and appropriate to their purpose. It should
|
|
be remembered that the Beans naming conventions do not apply to the
|
|
JDK as a whole; the AWT did adopt these conventions, but that
|
|
decision was somewhat controversial. We suspect that the
|
|
collections APIs will be used quite pervasively, often with
|
|
multiple method calls on a single line of code, so it is important
|
|
that the names be short. Consider, for example, the Iterator
|
|
methods. Currently, a loop over a collection looks like this:</p>
|
|
<pre>
|
|
for (Iterator i = c.iterator(); i.hasNext(); )
|
|
System.out.println(i.next());
|
|
</pre>
|
|
Everything fits neatly on one line, even if the Collection name is
|
|
a long expression. If we named the methods "getIterator",
|
|
"hasNextElement" and "getNextElement", this would no longer be the
|
|
case. Thus, we adopted the "traditional" JDK style rather than the
|
|
Beans style.</li>
|
|
</ol>
|
|
<hr>
|
|
<h2>Collection Interface</h2>
|
|
<ol>
|
|
<li><a id="a5"><b>Why doesn't Collection extend Cloneable
|
|
and Serializable?</b></a>
|
|
<p>Many Collection implementations (including all of the ones
|
|
provided by the JDK) will have a public clone method, but it would
|
|
be mistake to require it of all Collections. For example, what does
|
|
it mean to clone a Collection that's backed by a terabyte SQL
|
|
database? Should the method call cause the company to requisition a
|
|
new disk farm? Similar arguments hold for serializable.</p>
|
|
<p>If the client doesn't know the actual type of a Collection, it's
|
|
much more flexible and less error prone to have the client decide
|
|
what type of Collection is desired, create an empty Collection of
|
|
this type, and use the addAll method to copy the elements of the
|
|
original collection into the new one.</p>
|
|
</li>
|
|
<li><a id="a6"><b>Why don't you provide an "apply" method
|
|
in Collection to apply a given method ("upcall") to all the
|
|
elements of the Collection?</b></a>
|
|
<p>This is what is referred to as an "Internal Iterator" in the
|
|
"Design Patterns" book (Gamma et al.). We considered providing it,
|
|
but decided not to as it seems somewhat redundant to support
|
|
internal and external iterators, and Java already has a precedent
|
|
for external iterators (with Enumerations). The "throw weight" of
|
|
this functionality is increased by the fact that it requires a
|
|
public interface to describe upcalls.</p>
|
|
</li>
|
|
<li><a id="a7"><b>Why didn't you provide a "Predicate"
|
|
interface, and related methods (e.g., a method to find the first
|
|
element in the Collection satisfying the predicate)?</b></a>
|
|
<p>It's easy to implement this functionality atop Iterators, and
|
|
the resulting code may actually look cleaner as the user can inline
|
|
the predicate. Thus, it's not clear whether this facility pulls its
|
|
weight. It could be added to the Collections class at a later date
|
|
(implemented atop Iterator), if it's deemed useful.</p>
|
|
</li>
|
|
<li><a id="a8"><b>Why don't you provide a form of the
|
|
addAll method that takes an Enumeration (or an Iterator)?</b></a>
|
|
<p>Because we don't believe in using Enumerations (or Iterators) as
|
|
"poor man's collections." This was occasionally done in prior
|
|
releases, but now that we have the Collection interface, it is the
|
|
preferred way to pass around abstract collections of objects.</p>
|
|
</li>
|
|
<li><a id="a9"><b>Why don't the concrete implementations
|
|
in the JDK have Enumeration (or Iterator) constructors?</b></a>
|
|
<p>Again, this is an instance of an Enumeration serving as a "poor
|
|
man's collection" and we're trying to discourage that. Note
|
|
however, that we strongly suggest that all concrete implementations
|
|
should have constructors that take a Collection (and create a new
|
|
Collection with the same elements).</p>
|
|
</li>
|
|
<li><a id="a10"><b>Why don't you provide an Iterator.add
|
|
method?</b></a>
|
|
<p>The semantics are unclear, given that the contract for Iterator
|
|
makes no guarantees about the order of iteration. Note, however,
|
|
that ListIterator does provide an add operation, as it does
|
|
guarantee the order of the iteration.</p>
|
|
</li>
|
|
</ol>
|
|
<hr>
|
|
<h2>List Interface</h2>
|
|
<ol>
|
|
<li><a id="a11"><b>Why don't you rename the List
|
|
interface to Sequence; doesn't "list" generally suggest "linked
|
|
list"? Also, doesn't it conflict with java.awt.List?</b></a>
|
|
<p>People were evenly divided as to whether List suggests linked
|
|
lists. Given the implementation naming convention,
|
|
<<em>Implementation</em>><<em>Interface</em>>, there
|
|
was a strong desire to keep the core interface names short. Also,
|
|
several existing names (AbstractSequentialList, LinkedList) would
|
|
have been decidedly worse if we changed List to Sequence. The
|
|
naming conflict can be dealt with by the following incantation:</p>
|
|
<pre>
|
|
import java.util.*;
|
|
import java.awt.*;
|
|
import java.util.List; // Dictates interpretation of "List"
|
|
</pre></li>
|
|
<li><a id="a12"><b>Why don't you rename List's set
|
|
method to replace, to avoid confusion with Set.</b></a>
|
|
<p>It was decided that the "set/get" naming convention was strongly
|
|
enough enshrined in the language that we'd stick with it.</p>
|
|
</li>
|
|
</ol>
|
|
<hr>
|
|
<h2>Map Interface</h2>
|
|
<ol>
|
|
<li><a id="a14"><b>Why doesn't Map extend
|
|
Collection?</b></a>
|
|
<p>This was by design. We feel that mappings are not collections
|
|
and collections are not mappings. Thus, it makes little sense for
|
|
Map to extend the Collection interface (or vice versa).</p>
|
|
<p>If a Map is a Collection, what are the elements? The only
|
|
reasonable answer is "Key-value pairs", but this provides a very
|
|
limited (and not particularly useful) Map abstraction. You can't
|
|
ask what value a given key maps to, nor can you delete the entry
|
|
for a given key without knowing what value it maps to.</p>
|
|
<p>Collection could be made to extend Map, but this raises the
|
|
question: what are the keys? There's no really satisfactory answer,
|
|
and forcing one leads to an unnatural interface.</p>
|
|
<p>Maps can be <em>viewed</em> as Collections (of keys, values, or
|
|
pairs), and this fact is reflected in the three "Collection view
|
|
operations" on Maps (keySet, entrySet, and values). While it is, in
|
|
principle, possible to view a List as a Map mapping indices to
|
|
elements, this has the nasty property that deleting an element from
|
|
the List changes the Key associated with every element before the
|
|
deleted element. That's why we don't have a map view operation on
|
|
Lists.</p>
|
|
</li>
|
|
</ol>
|
|
<hr>
|
|
<h2>Iterator Interface</h2>
|
|
<ol>
|
|
<li><a id="a18"><b>Why doesn't Iterator extend
|
|
Enumeration?</b></a>
|
|
<p>We view the method names for Enumeration as unfortunate. They're
|
|
very long, and very frequently used. Given that we were adding a
|
|
method and creating a whole new framework, we felt that it would be
|
|
foolish not to take advantage of the opportunity to improve the
|
|
names. Of course we could support the new and old names in
|
|
Iterator, but it doesn't seem worthwhile.</p>
|
|
</li>
|
|
<li><a id="a19"><b>Why don't you provide an
|
|
Iterator.peek method that allows you to look at the next element in
|
|
an iteration without advancing the iterator?</b></a>
|
|
<p>It can be implemented atop the current Iterators (a similar
|
|
pattern to java.io.PushbackInputStream). We believe that its use
|
|
would be rare enough that it isn't worth including in the interface
|
|
that everyone has to implement.</p>
|
|
</li>
|
|
</ol>
|
|
<hr>
|
|
<h2>Miscellaneous</h2>
|
|
<ol>
|
|
<li><a id="a23"><b>Why did you write a new collections
|
|
framework instead of adopting JGL (a preexisting collections
|
|
package from ObjectSpace, Inc.) into the JDK?</b></a>
|
|
<p>If you examine the goals for our Collections framework (in the
|
|
Overview), you'll see that we are not really "playing in the same
|
|
space" as JGL. Quoting from the "Design Goals" Section of the Java
|
|
Collections Overview: "Our main design goal was to produce an API
|
|
that was reasonably small, both in size, and (more importantly) in
|
|
'conceptual weight.'"</p>
|
|
<p>JGL consists of approximately 130 classes and interfaces; its
|
|
main goal was consistency with the C++ Standard Template Library
|
|
(STL). This was <em>not</em> one of our goals. Java has
|
|
traditionally stayed away from C++'s more complex features (e.g.,
|
|
multiple inheritance, operator overloading). Our entire framework,
|
|
including all infrastructure, contains approximately 25 classes and
|
|
interfaces.</p>
|
|
<p>While this may cause some discomfort for some C++ programmers,
|
|
we feel that it will be good for Java in the long run. As the Java
|
|
libraries mature, they inevitably grow, but we are trying as hard
|
|
as we can to keep them small and manageable, so that Java continues
|
|
to be an easy, fun language to learn and to use.</p>
|
|
</li>
|
|
<li><a id="a26"><b>Why don't you eliminate all of the
|
|
methods and classes that return "views" (Collections backed by
|
|
other collection-like objects). This would greatly reduce
|
|
aliasing.</b></a>
|
|
<p>Given that we provide core collection interfaces behind which
|
|
programmers can "hide" their own implementations, there will be
|
|
aliased collections whether the JDK provides them or not.
|
|
Eliminating all views from the JDK would greatly increase the cost
|
|
of common operations like making a Collection out of an array, and
|
|
would do away with many useful facilities (like synchronizing
|
|
wrappers). One view that we see as being particularly useful is
|
|
<a href=
|
|
"../List.html#subList(int,int)">List.subList</a>.
|
|
The existence of this method means that people who write methods
|
|
taking List on input do not have to write secondary forms taking an
|
|
offset and a length (as they do for arrays).</p>
|
|
</li>
|
|
<li><a id="a27"><b>Why don't you provide for
|
|
"observable" collections that send out Events when they're
|
|
modified?</b></a>
|
|
<p>Primarily, resource constraints. If we're going to commit to
|
|
such an API, it has to be something that works for everyone, that
|
|
we can live with for the long haul. We may provide such a facility
|
|
some day. In the meantime, it's not difficult to implement such a
|
|
facility on top of the public APIs.</p>
|
|
</li>
|
|
</ol>
|
|
<hr>
|
|
<p style="font-size:smaller">
|
|
Copyright © 1998, 2017, Oracle and/or its affiliates. 500 Oracle Parkway<br>
|
|
Redwood Shores, CA 94065 USA. All rights reserved.</p>
|
|
<!-- Body text ends here -->
|
|
</body>
|
|
</html>
|