Вы находитесь на странице: 1из 15

A collection allows a group of objects to be treated as a single unit.

Arbitrary objects can


be stored, retrieved, and manipulated as elements of collections.

Program design often requires handling of groups of objects. The collections framework
presents a set of standard utility classes for managing such collections. This framework is
provided in the java.util package and comprises three main parts:

• The core interfaces that allow collections to be manipulated independently of their


implementation. These interfaces define the common functionality exhibited by
collections and facilitate data exchange between collections.

• A small set of implementations that are specific implementations of the core


interfaces, providing data structures that a program can use readily.
• An assortment of static utility methods that can be used to perform various
operations on collections, such as sorting and searching, or creating customized
collections.

Core Interfaces

The Collection interface is a generalized interface for maintaining collections, and is


the top of the interface inheritance hierarchy for collections .

Table 11.1. Core Interfaces in the Collections Framework

Interface Description Concrete


Classes
Collection A basic interface that defines the normal operations that
allow a collection of objects to be maintained or handled
as a single unit.
Set The Set interface extends the Collection interface to HashSet
LinkedHashSet
represent its mathematical namesake: a set of unique
elements.
SortedSet The SortedSet interface extends the Set interface to TreeSet
provide the required functionality for maintaining a set in
which the elements are stored in some sorted order.
List The List interface extends the Collection interface to ArrayList
maintain a sequence of elements that need not be unique. Vector
LinkedList

Map A basic interface that defines operations for maintaining HashMap


Hashtable
mappings of keys to values.
LinkedHashMap
Table 11.1. Core Interfaces in the Collections Framework

Interface Description Concrete


Classes
SortedMap Extends the Map interface for maps that maintain their TreeMap
mappings sorted in key order.

The elements in a Set must be unique, that is, no two elements in the set can be equal.
The order of elements in a List is retained, and individual elements can be accessed
according to their position in the list.

As can be seen from, the Map interface does not extend the Collection interface because
conceptually, a map is not a collection. A map does not contain elements. It contains
mappings (also called entries) from a set of key objects to a set of value objects. A key
can, at most, be associated with one value. As the name implies, the SortedMap interface
extends the Map interface to maintain its mappings sorted in key order.

11.2 Collections

The Collection interface specifies the contract that all collections should implement.
Some of the operations in the interface are optional, meaning that a collection may
choose to provide a stub implementation of such an operation that throws an
UnsupportedOperationException when invoked. The implementations of collections
from the java.util package support all the optional operations in the Collection
interface .Many of the methods return a boolean value to indicate whether the collection
was modified as a result of the operation.

Basic Operations

The basic operations are used to query a collection about its contents and allow elements
to be added and removed from a collection.

int size()
boolean isEmpty()
boolean contains(Object element)
boolean add(Object element) // Optional
boolean remove(Object element) // Optional

The add() and remove() methods return true if the collection was modified as a result
of the operation.

By returning the value false, the add() method indicates that the collection excludes
duplicates, and that the collection already contains an object equal to the argument object.

The contains() method checks for membership of the argument object in the collection
using object value equality.
Bulk Operations

These operations perform on a collection as a single unit.

boolean containsAll(Collection c)
boolean addAll(Collection c) // Optional
boolean removeAll(Collection c) // Optional
boolean retainAll(Collection c) // Optional
void clear() // Optional

These bulk operations can be used to perform the equivalent of set logic on arbitrary
collections (not just on sets). The containsAll() method returns true if all elements of
the specified collection are also contained in the current collection.

The addAll(), removeAll(), and retainAll() methods are destructive in the sense that the
collection on which they are invoked can be modified.

Array Operations

These operations convert collections to arrays.

Object[] toArray()
Object[] toArray(Object a[])

The first toArray() method returns an array with all the elements of the collection. The
second method stores the elements of a collection into an array of a specified type.

If the given array is big enough, the elements are stored in this array. If there is room to
spare in the array, that is, the length of the array is greater than the number of elements in
the collection, the spare room is filled with null values before the array is returned. If the
array is too small, a new array of the same runtime type and appropriate size is created.

Iterators

A collection provides an iterator which allows sequential access to the elements of a


collection. An iterator can be obtained by calling the following method of the
Collection interface:

Iterator iterator()

Returns an object which implements the Iterator interface.


The Iterator interface is defined as follows:

boolean hasNext()

Returns true if the underlying collection still has elements left to return. A future call to
the next() method will return the next element from the collection.

Object next()

Moves the iterator to the next element in the underlying collection, and returns the
current element. If there are no more elements left to return, it throws a
NoSuchElementException.

Object remove()

Removes the element that was returned by the last call to the next() method, from the
underlying collection. Invoking this method results in an IllegalStateException, if the
next() method has not yet been called, or when the remove() method has already been
called after the last call to the next() method. This method is optional for an iterator, that
is, it throws an UnsupportedOperationException if the remove operation is not
supported.

After obtaining the iterator for a collection, the methods provided by the Iterator
interface can be used to systematically traverse the elements of the underlying collection
one by one.

11.3 Sets

Unlike other implementations of the Collection interface, implementations of the Set


interface do not allow duplicate elements. This also means that a set can contain at most
one null value. The Set interface does not define any new methods, and its add() and
addAll() methods will not store duplicates. If an element is not currently in the set, two
consecutive calls to the add() method to insert the element will first return true, then
false.

Multisets (a.k.a. bags) that allow duplicate elements cannot be implemented using the
Set interface since this interface requires that elements are unique in the collection.
Table 11.3. Bulk Operations and Set Logic

Set Methods (a and b are sets) Corresponding Mathematical Operations


a.containsAll(b)
b a (subset)
a.addAll(b)
a = a b (union)
a.removeAll(b) a = a – b (difference)
a.retainAll(b)
a = a b (intersection)
a.clear() a = Ø (empty set)

HashSet and LinkedHashSet

The HashSet class implements the Set interface. Since this implementation uses a hash
table, it offers near constant-time performance for most operations. A HashSet does not
guarantee any ordering of the elements. However, the LinkedHashSet subclass of
HashSet guarantees insertion-order. The sorted counterpart is TreeSet. A HashSet relies
on the implementation of the hashCode() and equals() methods of its. The hashCode()
method is used for hashing the elements, and the equals() method is needed for
comparing elements. In fact, the equality and the hash codes of HashSets are defined in
terms of the equality and the hash codes of their elements.

As mentioned earlier, the LinkedHashSet implementation is a subclass of the HashSet


class. It works similarly to a HashSet, except for one important detail. Unlike a HashSet,
a LinkedHashSet guarantees that the iterator will access the elements in insertion order,
that is, in the order in which they were inserted into the LinkedHashSet.

The LinkedHashSet class offers constructors analogous to the ones in the HashSet class.
The initial capacity (i.e., the number of buckets in the hash table) and its load factor (i.e.,
the ratio of number of elements stored to its current capacity) can be tuned when the set is
created. The default values for these parameters will under most circumstances provide
acceptable performance.

HashSet()

Constructs a new, empty set.

HashSet(Collection c)
Constructs a new set containing the elements in the specified collection. The new set will
not contain any duplicates. This offers a convenient way to remove duplicates from a
collection.

HashSet(int initialCapacity)

Constructs a new, empty set with the specified initial capacity.

HashSet(int initialCapacity, float loadFactor)

Constructs a new, empty set with the specified initial capacity and the specified load
factor.

11.4 Lists

Lists are collections that maintain their elements in order, and can contain duplicates. The
elements in a list are ordered. Each element, therefore, has a position in the list. A zero-
based index can be used to access the element at the position designated by the index
value. The position of an element can change as elements are inserted or deleted from the
list.

In addition to the operations inherited from the Collection interface, the List interface
also defines operations that work specifically on lists: position-based access of the list
elements, searching in a list, creation of customized iterators, and operations on parts of a
list (called open range-view operations). This additional functionality is provided by the
following methods in the List interface:

// Element Access by Index


Object get(int index)

Returns the element at the specified index.

Object set(int index, Object element) Optional

Replaces the element at the specified index with the specified element. It returns the
previous element at the specified index.

void add(int index, Object element) Optional

Inserts the specified element at the specified index. If necessary, it shifts the element
previously at this index and any subsequent elements one position toward the end of the
list. The inherited method add(Object) from the Collection interface will append the
specified element to the end of the list.
Object remove(int index) Optional

Deletes and returns the element at the specified index, contracting the list accordingly.
The inherited method remove(Object) from the Collection interface will remove the
first occurrence of the element from the list.

boolean addAll(int index, Collection c) Optional

Inserts the elements from the specified collection at the specified index, using the iterator
of the specified collection. The method returns true if any elements were added.

In a non-empty list, the first element is at index 0 and the last element is at size()-1. As
might be expected, all methods throw an IndexOutOfBoundsException if an illegal
index is specified.

// Element Search
int indexOf(Object o)
int lastIndexOf(Object o)

These methods respectively return the index of the first and the last occurrence of the
element in the list if the element is found; otherwise, the value –1 is returned.

// List Iterators
ListIterator listIterator()
ListIterator listIterator(int index)

The iterator from the first method traverses the elements consecutively, starting with the
first element of the list, whereas the iterator from the second method starts traversing the
list from the element indicated by the specified index.

interface ListIterator extends Iterator {

boolean hasNext();
boolean hasPrevious();

Object next(); // Element after the cursor


Object previous(); // Element before the cursor

int nextIndex(); // Index of element after the cursor


int previousIndex(); // Index of element before the cursor

void remove(); // Optional


void set(Object o); // Optional
void add(Object o); // Optional
}

The ListIterator interface is a bidirectional iterator for lists. It extends the Iterator
interface and allows the list to be traversed in either direction. When traversing lists, it
can be helpful to imagine a cursor moving forward or backward between the elements
when calls are made to the next() and the previous() method, respectively. The
element that the cursor passes over is returned. When the remove() method is called, the
element last passed over is removed from the list.

// Open Range-View
List subList(int fromIndex, int toIndex)

This method returns a view of the list, which consists of the sublist of the elements from
the index fromIndex to the index toIndex-1. A view allows the range it represents in the
underlying list to be manipulated. Any changes in the view are reflected in the underlying
list, and vice versa. Views can be used to perform operations on specific ranges of a list.

ArrayList, LinkedList, and Vector

Three implementations of the List interface are provided in the java.util package:
ArrayList, LinkedList, and Vector.

The ArrayList class implements the List interface. The Vector class is a legacy class
that has been retrofitted to implement the List interface. The Vector and ArrayList
classes are implemented using dynamically resizable arrays, providing fast random
access and fast list traversal—very much like using an ordinary array. Unlike the
ArrayList class, the Vector class is thread-safe, meaning that concurrent calls to the
vector will not compromise its integrity.

The LinkedList implementation uses a doubly-linked list. Insertions and deletions in a


doubly-linked list are very efficient—elements are not shifted, as is the case for an array.
The LinkedList class provides extra methods that implement operations that add, get,
and remove elements at either end of a LinkedList:

void addFirst(Object obj)


void addLast(Object obj)
Object getFirst()
Object getLast()
Object removeFirst()
Object removeLast()

The ArrayList and Vector classes offer comparable performance, but Vector objects
suffer a slight performance penalty due to synchronization. Position-based access has
constant-time performance for the ArrayList and Vector classes. However, position-
based access is in linear time for a LinkedList, owing to traversal in a doubly-linked
list. When frequent insertions and deletions occur inside a list, a LinkedList can be
worth considering. In most cases, the ArrayList implementation is the over-all best
choice for implementing lists.
The ArrayList class provides the following constructors:

ArrayList()

Constructs a new, empty ArrayList. An analogous constructor is provided by the


LinkedList and Vector classes.

ArrayList(Collection c)

Constructs a new ArrayList containing the elements in the specified collection. The new
ArrayList will retain any duplicates. The ordering in the ArrayList will be determined
by the traversal order of the iterator for the collection passed as argument. An analogous
constructor is provided by the LinkedList and Vector classes.

ArrayList(int initialCapacity)

Constructs a new, empty ArrayList with the specified initial capacity. An analogous
constructor is provided by the Vector class.

11.5 Maps

A Map defines mappings from keys to values. The <key, value> pair is called an entry. A
map does not allow duplicate keys, in other words, the keys are unique. Each key maps to
one value at the most, implementing what is called a single-valued map. Thus, there is a
many-to-one relation between keys and values. For example, in a student-grade map, a
grade (value) can be awarded to many students (keys), but each student has only one
grade.

Both the keys and the values must be objects. This means that primitive values must be
wrapped in their respective wrapper objects, if they are to be put in a map.

A map is not a collection and the Map interface does not extend the Collection interface.
However, the mappings can be viewed as a collection in various ways: a key set, a value
collection, or an entry set. These collection views are the only means of traversing a map.

The Map interface specifies some optional methods. Implementations should throw an
UnsupportedOperationException if they do not support such an operation.

Basic Operations

These operations constitute the basic functionality provided by a map.

Object put(Object key, Object value) Optional

Inserts the <key, value> entry into the map. It returns the value previously associated
with the specified key, if any. Otherwise, it returns the null value.
Object get(Object key)

Returns the value to which the specified key is mapped, or null if no entry is found.

Object remove(Object key) Optional

The remove() method deletes the entry for the specified key. It returns the value
previously associated with the specified key, if any. Otherwise, it returns the null value.

boolean containsKey(Object key)

Returns true if the specified key is mapped to a value in the map.

boolean containsValue(Object value)

Returns true if there exists one or more keys that are mapped to the specified value.

int size()
boolean isEmpty()

These methods return the number of entries (i.e., number of unique keys in the map) and
whether the map is empty or not.

Bulk Operations

void putAll(Map t) Optional


void clear() Optional

The first method copies all entries from the specified map to the current map, and the
second method deletes all the entries from the current map.

Collection Views

Set keySet()
Collection values()
Set entrySet()

These methods provide different views of a map. Changes in the map are reflected in the
view, and vice versa. These methods return a set view of keys, a collection view of values
and a set view of <key, value> entries, respectively. Note that the Collection returned
by the values() method is not a Set, as several keys can map to the same value, that is,
duplicate values can be included in the returned collection. Each <key, value> in the
entry set view is represented by an object implementing the nested Map.Entry interface.
An entry in the entry set view can be manipulated by methods defined in this interface,
which are self-explanatory:

interface Entry {
Object getKey();
Object getValue();
Object setValue(Object value);
}

HashMap, LinkedHashMap, and Hashtable

The classes HashMap and Hashtable implement unordered maps. The class
LinkedHashMap implements ordered maps, which are discussed below. The class
TreeMap implements sorted maps .

While the HashMap class is not thread-safe and permits one null key, the Hashtable
class is thread-safe and permits non-null keys and values only. The thread-safety the
Hashtable class provides has a performance penalty. Thread-safe use of maps is also
provided by the methods in the Collections class. These map implementations are
based on a hashing algorithm. Operations on a map thus rely on the hashCode() and
equals() methods of the key objects

The LinkedHashMap implementation is a subclass of the HashMap class. The relationship


between the map classes LinkedHashMap and HashMap is analogous to the relationship
between their counterpart set classes LinkedHashSet and HashSet. Elements of a
HashMap (and a HashSet) are unordered. The elements of a LinkedHashMap (and a
LinkedHashSet) are ordered. By default, the entries of a LinkedHashMap are in key
insertion order, that is, the order in which the keys are inserted in the map. This order
does not change if a key is re-inserted, because no new entry is created if the key's entry
already exists from before. The elements in a LinkedHashSet are in (element) insertion
order. However, a LinkedHashMap can also maintain its elements in (element) access
order, that is, the order in which its entries are accessed, from least-recently accessed to
most-recently accessed entries. This ordering mode can be specified in one of the
constructors of the LinkedHashMap class.

Both the HashMap and LinkedHashMap classes provide comparable performance, but the
HashMap class is the natural choice if ordering is not an issue. Operations such as adding,
removing, or finding an entry based on a key are constant time, as these hash the key..

Adding, removing, and finding entries in a LinkedHashMap can be slightly slower than in
a HashMap, as an ordered doubly-linked list has to be maintained. Traversal of a map is
through one of its collection-views. For an underlying LinkedHashMap, the traversal time
is proportional to the size of the map—regardless of its capacity. However, for an
underlying HashMap, it is proportional to the capacity of the map.
The concrete map classes override the toString() method. The standard textual
representation generated by the toString() method for a map is

{key1=value1, key2=value2, ..., keyn=valuen}

where each keyi and each valuei is the textual representation generated by the
toString() method of the individual key and value objects in the map, respectively.

As was the case with collections, implementation classes provide a standard constructor
that creates a new empty map, and a constructor that creates a new map based on an
existing one. These classes also create a new empty map with an initial capacity and/or
load factor. The HashMap class provides the following constructors:

HashMap()
HashMap(int initialCapacity)
HashMap(int initialCapacity, float loadFactor)

Constructs a new, empty HashMap, using either specified or default initial capacity and
load factor.

HashMap(Map otherMap)

Constructs a new map containing the elements in the specified map.

The LinkedHashMap and Hashtable classes have constructors analogous to the four
constructors for the HashMap class. In addition, the LinkedHashMap class provides a
constructor where the ordering mode can also be specified:

LinkedHashMap(int initialCapacity, float loadFactor, boolean


accessOrder)

Constructs a new, empty LinkedHashMap with the specified initial capacity, the specified
load factor, and the specified ordering mode. The ordering mode is true for access order
and false for key insertion order.

11.6 Sorted Sets and Sorted Maps

Sets and maps have special interfaces, called SortedSet and SortedMap, for
implementations that sort their elements in a specific order .
Objects can specify their natural order by implementing the Comparable interface, or be
dictated a total order by a comparator object that implements the Comparator interface.

We'll first look at the two interfaces Comparable and Comparator, before discussing
sorted sets and maps.

The Comparator Interface

Precise control of ordering can be achieved by creating a customized comparator that


imposes a specific total ordering on the elements. All comparators implement the
Comparator interface, which has the following single method:

int compare(Object o1, Object o2)

The compare() method returns a negative integer, zero, or a positive integer if the first
object is less than, equal to, or greater than the second object, according to the total order.
Since this method tests for equality, it is strongly recommended that its implementation
does not contradict the semantics of the equals() method (see Section 11.7).
The Comparable Interface

A class can define the natural order of its instances by implementing the Comparable
interface. Many of the standard classes in the Java API, such as the wrapper classes,
String, Date, and File, implement this interface. The java.lang.Comparable interface
specifies a single method:

int compareTo(Object o)

This method returns a negative integer, zero, or a positive integer if the current object is
less than, equal to, or greater than the specified object, based on the natural order. It
throws a ClassCastException if the reference value passed in the argument cannot be
cast to the type of the current object. Since this method tests for equality, it is
recommended that its implementation does not contradict the semantics of the equals()
method.

Objects implementing this interface can be used as

• elements in a sorted set


• keys in a sorted map
• elements in lists that are sorted manually using the Collections.sort() method

Note that the natural order for String objects (and Character objects) is lexicographical
order. Strings will be lexicographically maintained as elements in a sorted set or as keys
in a sorted map that uses natural ordering. A collection of strings sorted by natural order
would be ordered in lexicographical order.

The natural order for objects of a numerical wrapper type is ascending order of the values
of the corresponding numerical primitive type. As elements in a sorted set, or as keys in a
sorted map, the objects would be maintained in ascending order.

An alternative ordering to the default natural order can be specified by passing a


Comparator to the constructor when the sorted set or map is created. The Collections
and Arrays classes provide utility methods for sorting, which also take a Comparator

Вам также может понравиться