Chapter 3
IN THIS CHAPTER
Working with the ArrayList class
Creating an array list
Introducing generics
Adding elements to an array list
Deleting elements from or modifying elements in an array list
Some people love to collect things: nick-knacks, baseball cards, postage stamps, dolls — you name it, someone collects it.
If I were a collector of some random thing — say, old tin advertising signs — an array would be a poor choice for storing the data. That’s because on any given day, I may find another tin sign at a yard sale. So if I had 87 tin signs before, and I had created an array big enough to hold all 87 signs, I’d have to change the array declaration to hold 88 signs.
Java’s collection classes are designed to simplify the programming for applications that have to keep track of groups of objects. These classes are very powerful and surprisingly easy to use — at least the basics, anyway. The more advanced features of collection classes take some serious programming to get right, but for most applications, a few simple methods are all you need to use collection classes.
Unfortunately, Java’s collection classes are organized according to a pretty complicated inheritance hierarchy that can be very confusing for beginners. Most of the Java books I have on my shelf start by explaining this inheritance scheme and showing how each of the various collection classes fits into this scheme, and why.
I’m not going to do that. I think it’s very confusing for newcomers to collections to have to wade through a class hierarchy that doesn’t make sense until they know some of the details of how the basic classes work. Instead, I just show you how to use two of the best of these classes.
In this chapter, you find out how to use the
ArrayList
class. Then, in the next chapter, you find out how to use its first cousin, the
LinkedList
. When you know how to use these two classes, you shouldn’t have any trouble figuring out how to use the other collection classes from the API documentation.
Because generics are an integral part of how collections work in Java 1.5 and subsequent versions, I incorporate the generics feature into this chapter from the very start. I point out the differences for using
ArrayList
without generics along the way, just in case you’re using an older version of Java or are working with programs that were written before Java 1.5 became available. (For a complete explanation of how the generics feature works, you can move ahead to Book 4, Chapter 5
.)
I have even more good news about new features: the major new feature that was introduced with Java 8, lambda expressions, provides an entirely new way of working with collections that is especially useful for efficiently dealing with collections that have a large number of items. For more information about working with these new collection features, see Chapter 6 of this minibook. And for more information about lambda expressions, see Book 3, Chapter 7 .
An array list is the most basic type of Java collection. You can think of an array list as being an array on steroids. It’s similar to an array but averts many of the most common problems of working with arrays, specifically the following:
The
ArrayList
class actually uses an array internally to store the data you add to the array list.
The
ArrayList
class takes care of managing the size of this array. When you add an item to the array list, and the underlying array is full, the
ArrayList
class automatically creates a new array with a larger capacity and copies the existing items to the new array before it adds the new item.
The
ArrayList
class has several constructors and a ton of methods. For your reference, Table 3-1
lists the constructors and methods of the
ArrayList
class.
TABLE 3-1 The ArrayList Class
Constructor |
Explanation |
|
Creates an array list with an initial capacity of ten elements. |
|
Creates an array list with the specified initial capacity. |
|
Creates an array list and copies all the elements from the specified collection into the new array list. |
Method |
Explanation |
|
Adds the specified object to the array list. If you specified a type when you created the array list, the object must be of the correct type. |
|
Adds the specified object to the array list at the specified index position. If you specified a type when you created the array list, the object must be of the correct type. |
|
Adds all the elements of the specified collection to this array list. |
|
Adds all the elements of the specified collection to this array list at the specified index position. |
|
Deletes all elements from the array list. |
|
Returns a shallow copy of the array list. The elements contained in the copy are the same object instances as the elements in the original. |
|
Returns a
|
|
Returns a
|
|
Increases the array list’s capacity to the specified value. (If the capacity is already greater than the specified value, this method does nothing.) |
|
Returns the object at the specified position in the list. |
|
Returns the index position of the first occurrence of the specified object in the array list. If the object isn’t in the list, it returns
|
|
Returns a
|
|
Returns an iterator for the array list. |
|
Returns the index position of the last occurrence of the specified object in the array list. If the object isn’t in the list, it returns
|
|
Removes the object at the specified index and returns the element that was removed. |
|
Removes an object from the list. Note that more than one element refers to the object; this method removes only one of them. It returns a
|
|
Removes all objects whose index values are between the values specified. Note that the elements at the
|
|
Removes all the objects in the specified collection from this array list. |
|
Removes all the objects that are not in the specified collection from this array list. |
|
Sets the specified element to the specified object. The element that was previously at that position is returned as the method’s return value. |
|
Returns the number of elements in the list. |
|
Returns the elements of the array list as an array of objects (
|
|
Returns the elements of the array list as an array whose type is the same as the array passed via the parameter. |
The rest of this chapter shows you how to use these constructors and methods to work with
ArrayList
objects.
To create an array list, you first declare an
ArrayList
variable and then call the
ArrayList
constructor to instantiate an
ArrayList
object and assign it to the variable. You can do this on separate lines:
ArrayList signs;
signs = new ArrayList();
Alternatively, you can do it on a single line:
ArrayList signs = new ArrayList();
Here are a few things to note about creating array lists:
The
ArrayList
class is in the
java.util
package, so your program must import either
java.util.ArrayList
or
java.util.*
.
ArrayList signs = new ArrayList(100);
If you don’t specify a capacity for the array list, the initial capacity is set to
10
. Providing at least a rough estimate of how many elements each array list can hold when you create it is a good idea.
The capacity of an array list is not a fixed limit. The
ArrayList
class automatically increases the list’s capacity whenever necessary.
If you’re using Java 1.5 or later, you can also specify the type of elements the array list is allowed to contain. This statement creates an array list that holds
String
objects:
ArrayList<String> signs = new ArrayList<String>();
The advantage of specifying a type when you declare an array list is that the compiler complains if you then try to add an object of the wrong type to the list. (This feature is called generics because it lets the Java API designers create generic collection classes that can be used to store any type of object. For more information, see Book 4, Chapter 5 .)
ArrayList
class also has a constructor that lets you specify another collection object (typically, another array list) whose items are copied into the new array list. This provides an easy way to make a copy of an array list, but you can also use it to convert any other type of collection to an array list.After you create an array list, you can use the
add
method to add objects to the array list. Here’s code that adds strings to an array list:
signs.add("Drink Pepsi");
signs.add("No minors allowed");
signs.add("Say Pepsi, Please");
signs.add("7-Up: You Like It, It Likes You");
signs.add("Dr. Pepper 10, 2, 4");
If you specified a type when you created the array list, the objects you add via the
add
method must be of the correct type.
You can insert an object at a specific position in the list by listing the position in the
add
method. Consider these statements:
ArrayList<String> nums = new ArrayList<String>();
nums.add("One");
nums.add("Two");
nums.add("Three");
nums.add("Four");
nums.add(2, "Two and a half");
After these statements execute, the
nums
array list contains the following strings:
One
Two
Two and a half
Three
Four
Here are some important points to keep in mind when you add elements to array lists:
If an array list is already at its capacity when you add an element, the array list automatically expands its capacity. Although this capacity is flexible, it’s also inefficient. Whenever possible, you should anticipate how many elements you’re adding to an array list and set the list’s initial capacity accordingly. (You can also change the capacity at any time by calling the
ensureCapacity
method
.)
add
method that accepts an index number.
The
add
method that inserts elements at a specific index position throws the unchecked exception
IndexOutOfBoundsException
if an object isn’t already at the index position you specify.
To access a specific element in an array list, you can use the
get
method, which specifies the index value of the element you want to retrieve. Here’s a
for
loop that prints all the strings in an array list:
for (int i = 0; i < nums.size(); i++)
System.out.println(nums.get(i));
Here the
size
method is used to set the limit of the
for
loop’s index variable.
The easiest way to access all the elements in an array list is to use an enhanced
for
statement, which lets you retrieve the elements without bothering with indexes or the
get
method. For example:
for (String s : nums)
System.out.println(s);
Here each
String
element in the
nums
array list is printed to the console.
If you need to know the index number of a particular object in an array list, and you have a reference to the object, you can use the
indexOf
method. Here’s an enhanced
for
loop that prints the index number of each string along with the string:
for (String s : nums)
{
int i = nums.indexOf(s);
System.out.println("Item " + i + ": " + s);
}
Depending on the contents of the array list, the output from this loop may look something like this:
Item 0: One
Item 1: Two
Item 2: Three
Item 3: Four
The
toString
method of the
ArrayList
class (as well as other collection classes) is designed to make it easy to quickly print out the contents of the list. It returns the contents of the array list enclosed in a set of brackets, with each element value separated by commas. The
toString
method of each element is called to obtain the element value.
Consider these statements:
ArrayList<String> nums = new ArrayList<String>();
nums.add("One");
nums.add("Two");
nums.add("Three");
nums.add("Four");
System.out.println(nums);
When you run these statements, the following is displayed on the console:
[One, Two, Three, Four]
Although this output isn’t very useful for actual applications, it’s convenient for testing purposes or for debugging problems in programs that use array lists.
Another way to access all the elements in an array list (or any other collection type) is to use an iterator. An iterator is a special type of object whose sole purpose in life is to let you step through the elements of a collection.
An iterator object implements the
Iterator
interface, which is defined as part of the
java.util
package. As a result, to use an iterator, you must import either
java.util.Iterator
or
java.util.*
. The
Iterator
interface defines just three methods, as listed in Table 3-2
. These methods are all you need to access each element of a collection. (Actually, you need only the
hasNext
and
next
methods. The
remove
method is gravy.)
TABLE 3-2 The Iterator Interface
Method |
Explanation |
|
Returns
|
|
Returns the next element in the collection |
|
Removes the most recently retrieved element |
To use an iterator, you first call the array list’s
iterator
method to get the iterator. Then you use the iterator’s
hasNext
and
next
methods to retrieve each item in the collection. The normal way to do that is with a
while
loop. Here’s an example:
ArrayList<String> nums = new ArrayList<String>();
nums.add("One");
nums.add("Two");
nums.add("Three");
nums.add("Four");
String s;
Iterator e = nums.iterator();
while (e.hasNext())
{
s = (String)e.next();
System.out.println(s);
}
Here the first five statements create an array list and add four strings to it. Next, the
iterator
method is called to get an iterator for the
nums
array list. The
hasNext
method is called in the
while
statement, and the
next
method is called to get the element to be printed.
You can use the
set
method to replace an existing object with another object. Consider this example:
ArrayList<String> nums = new ArrayList<String>();
nums.clear();
nums.add("One");
nums.add("Two");
nums.add("Three");
System.out.println(nums);
nums.set(0, "Uno");
nums.set(1, "Dos");
nums.set(2, "Tres");
System.out.println(nums);
Here an array list is created with three strings, and the contents of the array list are printed to the console. Then each of the three strings is replaced by another string, and the contents print to the console again. When you run this code, the following is what you see printed on the console:
[One, Two, Three]
[Uno, Dos, Tres]
For example:
ArrayList<Employee> emps = new ArrayList<Employee>();
// add employees to array list
emps.add(new Employee("Addams", "Gomez"));
emps.add(new Employee("Taylor", "Andy"));
emps.add(new Employee("Kirk", "James"));
// print array list
System.out.println(emps);
// change one of the employee's names
Employee e = emps.get(1);
e.changeName("Petrie", "Robert");
// print the array list again
System.out.println(emps);
This example uses the
Employee
class, whose constructor accepts an employee’s last name and first name to create a new employee object, as well as a
changeName
method that also accepts a last name and a first name. In addition, the
Employee
class overrides the
toString
method to return the employee’s first name and last name.
The
main
method begins by creating an
ArrayList
object and adding three employees. Then it prints out the contents of the array list. Next, it retrieves the employee with index number
1
and changes that employee’s name. Finally, it prints the contents of the array list again.
Here’s what this code produces on the console:
[Gomez Addams, Andy Taylor, James Kirk]
[Gomez Addams, Robert Petrie, James Kirk]
Notice that the second employee’s name was changed, even though the program doesn’t use the
set
method to replace the changed
Employee
object in the collection. That’s because the array list merely stores references to the
Employee
objects.
The
ArrayList
class provides several methods that let you remove elements from the collection. To remove all the elements, use the
clear
method, like this:
emps.clear();
To remove a specific element, use the
remove
method. It lets you remove an element based on the index number, like this:
emps.remove(0);
Here the first element in the array list is removed.
Alternatively, you can pass the actual object you want removed. This is useful if you don’t know the index of the object you want to remove, but you happen to have a reference to the actual object, as in this example:
ArrayList<Employee> emps = new ArrayList<Employee>();
// create employee objects
Employee emp1 = new Employee("Addams", "Gomez");
Employee emp2 = new Employee("Taylor", "Andy");
Employee emp3 = new Employee("Kirk", "James");
// add employee objects to array list
emps.add(emp1);
emps.add(emp2);
emps.add(emp3);
// print the array list
System.out.println(emps);
// remove one of the employees
emps.remove(emp2);
// print the array list again
System.out.println(emps);
Here’s what this code produces on the console:
[Gomez Addams, Andy Taylor, James Kirk]
[Gomez Addams, James Kirk]
As you can see, the program was able to remove
Andy Taylor
from the list without knowing his index position.
Here are a few important details to keep in mind:
clear
and
remove
methods don’t actually delete objects; they simply remove the references to the objects from the array list. Like any other objects, the objects in a collection are deleted automatically by the garbage collector — and then only if the objects are no longer being referenced by the program.removeRange
method. On it, you specify the starting and ending index numbers. (Note that this method removes all elements between the elements you specify, but the elements you specify aren’t themselves removed.
removeRange(5, 8)
, for example, removes elements 6 and 7, but elements 5 and 8 aren’t removed.)
You can also use the
removeAll
method to remove all the objects in one collection from another collection. A similar method,
retainAll
, removes all the objects that are not
in another collection.