AhmadLang / Java, How To Program, 2004
.pdf
[Page 910 (continued)]
19.4. Interface Collection and Class Collections
Interface Collection is the root interface in the collection hierarchy from which interfaces Set, Queue and List are derived. Interface Set defines a collection that does not contain duplicates. Interface Queue defines a collection that represents a waiting linetypically, insertions are made at the back of a queue and deletions are made from the front, though other orders can be specified. We discuss Queue and Set in Section 19.8 and Section 19.9, respectively. Interface Collection contains bulk operations (i.e., operations performed on an entire collection) for adding, clearing, comparing and retaining objects (or elements) in a collection. A Collection can also be converted to an array. In addition, interface Collection provides a method that returns an Iterator object, which allows a program to walk through the collection and remove elements from the collection during the iteration. We discuss class Iterator in Section 19.5.1. Other methods of interface Collection enable a program to determine a collection's size and whether a collection is empty.
Software Engineering Observation 19.1
Collection is used commonly as a method parameter type to allow polymorphic processing of all objects that implement interface
Collection.
Software Engineering Observation 19.2
Most collection implementations provide a constructor that takes a Collection argument, thereby allowing a new collection to be constructed containing the elements of the specified collection.
Class Collections provides static methods that manipulate collections polymorphically. These methods implement algorithms for searching, sorting and so on. Chapter 16, Searching and Sorting, discussed and implemented various searching and sorting algorithms. Section 19.6 discusses more about the algorithms that are available in class Collections. We also cover the wrapper methods of class Collections that enable you to treat a collection as a synchronized collection (Section 19.12) or an unmodifiable collection (Section 19.13). Unmodifiable collections are useful when a client of a class needs to view the elements of a collection, but should not be allowed to modify the collection by adding and removing elements. Synchronized collections are for use with a powerful capability called multithreading (discussed in Chapter 23). Multithreading enables programs to perform operations in parallel. When two or more threads of a program share a collection, there is the potential for problems to occur. As a brief analogy, consider a traffic intersection. We cannot allow all cars access to one intersection at the same timeif we did, accidents would occur. For this reason, traffic lights are provided at intersections to control access to the intersection. Similarly, we can synchronize access to a collection to ensure that only one thread manipulates the collection at a time. The synchronization wrapper methods of class collection return synchronized versions of collections that can be shared among threads in a program.
1// Fig. 19.4: ListTest.java
2// Using LinkLists.
3import java.util.List;
4import java.util.LinkedList;
5import java.util.ListIterator;
7public class ListTest
8{
9private static final String colors[] = { "black", "yellow",
10"green", "blue", "violet", "silver" };
11private static final String colors2[] = { "gold", "white",
12"brown", "blue", "gray", "silver" };
13
14// set up and manipulate LinkedList objects
15public ListTest()
16{
17List< String > list1 = new LinkedList< String >();
18List< String > list2 = new LinkedList< String >();
20// add elements to list link
21for ( String color : colors )
22 |
list1.add( color ); |
23 |
|
24// add elements to list link2
25for ( String color : colors2 )
26list2.add( color );
27
28list1.addAll( list2 ); // concatenate lists
29list2 = null; // release resources
30printList( list1 ); // print list1 elements
32convertToUppercaseStrings( list1 ); // convert to upper case string
33printList( list1 ); // print list1 elements
35System.out.print( "\nDeleting elements 4 to 6..." );
36removeItems( list1, 4, 7 ); // remove items 4-7 from list
37printList( list1 ); // print list1 elements
38printReversedList( list1 ); // print list in reverse order
39} // end ListTest constructor
40
41// output List contents
42public void printList( List< String > list )
43{
44System.out.println( "\nlist: " );
45
46for ( String color : list )
47System.out.printf( "%s ", color );
49System.out.println();
50} // end method printList
52// locate String objects and convert to uppercase
53private void convertToUppercaseStrings( List< String > list )
54{
55ListIterator< String > iterator = list.listIterator();
57while ( iterator.hasNext() )
58{
59String color = iterator.next(); // get item
60iterator.set( color.toUpperCase() ); // convert to upper case
61} // end while
62} // end method convertToUppercaseStrings
63 |
|
|
|
|
|
64 |
// obtain sublist and use clear method |
to |
delete sublist |
items |
|
65 |
private void removeItems( List< String |
> list, int |
start, |
int end ) |
|
66 |
{ |
|
|
|
|
67 |
list.subList( start, end ).clear(); |
// |
remove |
items |
|
68 |
} // end method removeItems |
|
|
|
|
69 |
|
|
|
|
|
70// print reversed list
71private void printReversedList( List< String > list )
72{
73ListIterator< String > iterator = list.listIterator( list.size() );
75System.out.println( "\nReversed List:" );
76
77// print list in reverse order
78while ( iterator.hasPrevious() )
79System.out.printf( "%s ", iterator.previous() );
80} // end method printReversedList
81
82public static void main( String args[] )
83{
84new ListTest();
85} // end main
86} // end class ListTest
list:
black yellow green blue violet silver gold white brown blue gray silver
list:
BLACK YELLOW GREEN BLUE VIOLET SILVER GOLD WHITE BROWN BLUE GRAY SILVER
Deleting elements 4 to 6...
list:
BLACK YELLOW GREEN BLUE WHITE BROWN BLUE GRAY SILVER
Reversed List:
SILVER GRAY BLUE BROWN WHITE BLUE GREEN YELLOW BLACK
[Page 916]
Lines 1718 create LinkedLists list1 and list2 of type String. Note that LinkedList is a generic class that has one type parameter for which we specify the type argument String in this example. Lines 2126 call List method add to append elements from arrays colors and colors2 to the end of list1 and list2, respectively.
Line 28 calls List method addAll to append all elements of list2 to the end of list1. Line 29 sets list2 to null, so the LinkedList to which list2 referred can be garbage collected. Line 30 calls method printList (lines 4250) to output list list1's contents. Line 32 calls method convertToUppercaseStrings (lines 5362) to convert each String element to uppercase, then line 33 calls printList again to display the modified Strings. Line 36 calls method removeItems (lines 6568) to remove the elements starting at index 4 up to, but not including, index 7 of the list. Line 38 calls method printReversedList (lines 7180) to print the list in reverse order.
Method convertToUppercaseStrings (lines 5362) changes lowercase String elements in its List argument to uppercase Strings. Line 55 calls List method listIterator to get a bidirectional iterator (i.e., an iterator that can traverse a List backward or forward) for the List. Note that ListIterator is a generic class. In this example, the ListIterator contains String objects, because method listIterator is called on a List of Strings. The while condition (line 57) calls method hasNext to determine whether the List contains another element. Line 59 gets the next String in the List. Line 60 calls String method toUpperCase to get an uppercase version of the String and calls ListIterator method set to replace the current String to which iterator refers with the String returned by method toUpperCase. Like method toUpperCase, String method toLowerCase returns a lowercase version of the String.
Method removeItems (lines 6568) removes a range of items from the list. Line 67 calls List method subList to obtain a portion of the List (called a sublist). The sublist is simply another view into the List on which subList is called. Method subList takes two argumentsthe beginning and the ending index for the sublist. The ending index is not part of the range of the sublist. In this example, we pass (in line 36) 4 for the beginning index and 7 for the ending index to subList. The sublist returned is the set of elements with indices 4 tHRough 6. Next, the program calls List method clear on the sublist to remove the elements of the sublist from the List. Any changes made to a sublist are also made to the original
List.
Method printReversedList (lines 7180) prints the list backward. Line 73 calls List method listIterator with one argument that specifies the starting position (in our case, the last element in the list) to get a bidirectional iterator for the list. List method size returns the number of items in the List. The while
condition (line 78) calls method hasPrevious to determine whether there are more elements while traversing the list backward. Line 79 gets the previous element from the list and outputs it to the standard output stream.
An important feature of the collections framework is the ability to manipulate the elements of one collection type (such as a set) through a different collection type (such as a list), regardless of the collection's internal implementation. The set of public methods through which collections are manipulated is called a view.
Class Arrays provides static method asList to view an array as a List collection (which encapsulates behavior similar to that of the linked lists created in Chapter 17). A List view allows the programmer to manipulate the array as if it were a list. This is useful for adding the elements in an array to a collection (e.g., a LinkedList) and for sorting array elements. The next example demonstrates how to create a LinkedList with a List view of an array, because we cannot pass the array to a LinkedList constructor. Sorting array elements with a List view is demonstrated in Fig. 19.9. Any modifications made through the List view change the array, and any modifications made to the array change the List view. The only operation permitted on the view returned by asList is set, which changes the value of the view and the backing array. Any other attempts to change the view (such as adding or removing elements) result in an UnsupportedOperationException.
[Page 917]
Figure 19.5 uses method asList to view an array as a List collection and uses method toArray of a List to get an array from a LinkedList collection. The program calls method asList to create a List view of an array, which is then used for creating a LinkedList object, adds a series of strings to a LinkedList and calls method toArray to obtain an array containing references to the strings. Notice that the instantiation of LinkedList (line 13) indicates that LinkedList is a generic class that accepts one type argumentString, in this example.
Figure 19.5. List method toArray.
(This item is displayed on pages 917 - 918 in the print version)
1// Fig. 19.5: UsingToArray.java
2// Using method toArray.
3import java.util.LinkedList;
4import java.util.Arrays;
5
6public class UsingToArray
7{
8 // constructor creates LinkedList, adds elements and converts to array
9public UsingToArray()
10{
11String colors[] = { "black", "blue", "yellow" };
13LinkedList< String > links =
14new LinkedList< String >( Arrays.asList( colors ) );
16 |
links.addLast( "red" ); |
// add as last item |
||||||
17 |
links.add( |
"pink" ); |
|
// |
add |
to |
the |
end |
18 |
links.add( |
3, "green" |
); |
// |
add |
at |
3rd |
index |
19 |
links.addFirst( "cyan" |
); |
// |
add |
as |
first item |
||
20 |
|
|
|
|
|
|
|
|
21// get LinkedList elements as an array
22colors = links.toArray( new String[ links.size() ] );
24System.out.println( "colors: " );
26for ( String color : colors )
27System.out.println( color );
28} // end UsingToArray constructor
30public static void main( String args[] )
31{
32new UsingToArray();
33} // end main
34} // end class UsingToArray
Performance Tip 19.2
Inserting an element into a Vector whose current size is less than its capacity is a relatively fast operation.
Performance Tip 19.3
Inserting an element into a Vector that needs to grow larger to accommodate the new element is a relatively slow operation.
Performance Tip 19.4
The default capacity increment doubles the size of the Vector. This may seem a waste of storage, but it is actually an efficient way for many Vectors to grow quickly to be "about the right size." This operation is much more efficient than growing the Vector each time by only as much space as it takes to hold a single element. The disadvantage is that the Vector might occupy more space than it requires. This is a classic example of the spacetime trade-off.
Performance Tip 19.5
If storage is at a premium, use Vector method trimToSize to trim a Vector's capacity to the Vector's exact size. This operation optimizes a Vector's use of storage. However, adding another element to the Vector will force the Vector to grow dynamically (again, a relatively slow operation)trimming leaves no room for growth.
Figure 19.6 demonstrates class Vector and several of its methods. For complete information on class Vector, please visit java.sun.com/j2se/5.0/docs/api/java/util/Vector.html.
Figure 19.6. Vector class of package java.util.
(This item is displayed on pages 919 - 921 in the print version)
1// Fig. 19.6: VectorTest.java
2// Using the Vector class.
3import java.util.Vector;
4import java.util.NoSuchElementException;
6public class VectorTest
7{

vector is empty