ArrayList
The first collection class we will look at is the ArrayList class. This class is essentially a
resizable array – the class stores the elements in an array, but if that array gets full as elements
are added, it makes it bigger. When we are using the ArrayList class, though, we don’t see
anything about the array. All we see is the ability to add elements, remove elements, find
elements, etc. – but we do all of this through method calls.
Creating an ArrayList
To create an ArrayList object, we do:
ArrayList<type> name = new ArrayList<type>();Here, type is the type of elements we want to store, and name is the variable name we’re
giving to this ArrayList. For example, to create an ArrayList that holds a bunch of
names, we might do:
ArrayList<String> namesList = new ArrayList<String>();Adding elements
Once we’ve created a new ArrayList object, we can add elements to our list. This is done
with the syntax:
name.add(elem);Where name is the name of our ArrayList, and elem has the same type we specified when
creating that list. For example, we could add names to our namesList object as follows:
namesList.add("Bob");
namesList.add("Jane");
namesList.add("Joe");
namesList.add("Mary");An ArrayList stores elements in the same way you would expect things to be stored in the
array (because the class itself uses an array to store the elements). After adding those four
names, we can think of “Bob” being at index 0, “Jane” being at index 1, etc.
Changing elements
Once we have stored values in an ArrayList, we can change their value by specifying the
index we’re after and the new value we want to use. Here is the syntax:
name.set(index, elem);Where index is the position we want to change (thinking of the ArrayList like an array),
and elem is the new value we wish to store. For example, if we do:
namesList.set(1, "Allison");Then the new list of values in namesList is: {"Bob", "Allison", "Joe", "Mary"}.
We cannot use this syntax to change a position that has not been added yet. For example, if we
try:
namesList.set(5, "Fred");Then an exception will be thrown, as there is not currently an element at position 5.
Getting elements
We can also access elements in an ArrayList much like we can access elements in an array –
by specifying the index we want. We can do this with the syntax:
name.get(index)Where index is the position of the element we would like to access. This method call returns
the element at that position, so we will usually want to store the result of the method call in a
variable whose type matches the type of elements we’re storing. For example, we could do:
String first = namesList.get(0);To get the first name in namesList. Our first variable will now have the value “Bob”.
We can also use this method to help us access every element in an ArrayList, using the
syntax name.size() to determine how many elements are in the list. For example, we can
print every element in namesList like this:
for (int i = 0; i < namesList.size(); i++)
{
System.out.println(namesList.get(i));
}This will print:
Bob
Allison
Joe
MaryRemoving elements
We can also remove elements from our list by specifying the index of the element we wish to remove. Any element that was behind the one we’re removing will be shifted down to fill the empty spot. The syntax is:
name.remove(index)Where index is the position with the element we wish to remove. This method does return the
element that is removed, so you can optionally store the result of the method call in a variable
with the same type as the elements being stored.
For example, we can do:
namesList.remove(1);This removes “Allison” from our list, and shifts up “Joe” and “Mary” to fill the hole. Now the contents of the list are: Bob at index 0, Joe at index 1, and Mary at index 2.
Auto-boxing and auto-unboxing
In Java, variable types such as int, double, char, and boolean are called primitive types. Other
types (which are defined by a Java class or one of our own classes), like String, StringTokenizer,
Random, Person (if we had written a Person class), etc. are called reference types. The
difference between these types is a bit beyond the scope of this class, but it has to do with how
these variables are stored in memory. Memory space for primitive variables is always allocated
before the program runs, but memory space for reference types (objects) is not allocated until the
program is already running. Moreover, a primitive variable actually holds a value, while a
reference variable holds the memory address of where that object is in memory.
In any case, Java Collections are only designed to hold reference types. However, there are
special reference types in Java (called wrapper classes) whose purpose is to turn a primitive type
into a reference type. The three such classes we will look at are: Integer, Double, and
Character. For example, we can do:
int x = 4;
Integer val = new Integer(x);This essentially turns the primitive int 4 into a reference type that wraps around the value 4. So if we want to store primitive types like ints in an `ArrayList’ (or any Java collection), we could try something like this:
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(new Integer(4));
nums.add(new Integer(10));
nums.add(new Integer(2));If we wanted to get the value at index 1 (the 10), we could do:
Integer val = nums.get(1);And then if we wanted to turn it back into a regular int, we could use the intValue method:
int x = val.intValue();Now x would have the value 10. We notice, though, that having to deal with primitive types in
this way is cumbersome and annoying. To smooth this process, Java has an auto-boxing/auto-unboxing feature that automatically converts between primitive types like int, double, char and
their wrapper types. For example, we could create our nums list from above like this:
ArrayList<Integer> nums = new ArrayList<Integer>();
nums.add(4);
nums.add(10);
nums.add(2);When we pass in an int to be added to the list, that int is automatically converted to an Integer
(this is called auto-boxing). We can also do:
int x = nums.get(1);And the Integer at position 1 is automatically converted to an int (this is called auto-unboxing). We can do something similar with double/Double and char/Character.
Iterator
An iterator is a tool in Java to help us step through each element in a collection. With an
ArrayList, it is just as easy to loop through each index (with a for loop) and call get to access
each value, but the same is not true of other collections.
Suppose we have this ArrayList:
ArrayList<Double> vals = new ArrayList<Double>();
Scanner s = new Scanner(System.in);
for (int i = 0; i < 10; i++)
{
System.out.print("Enter a value: ");
double x = s.nextDouble();
vals.add(x);
}Here is how we can access and print each value in the list using an Iterator:
Iterator<Double> it = vals.iterator();
while (it.hasNext())
{
double cur = it.next();
System.out.println(cur);
}We will be able to use this same style of looping through elements with an Iterator in other
Java Collections.
For-each loop
We can also loop over each element in an ArrayList using a for-each loop. For example, we could rewrite our while loop
above that used an iterator to print each element in vals using a for-each loop:
for (Integer cur : vals)
{
System.out.println(cur);
}When we write a for-each loop over a collection, it is automatically translated by the compiler into the previous code that used an iterator.
Example
In this section, we will write a bigger example that uses an ArrayList. Suppose that we want
to read information about a group of people from a file. Each line in the file (info.txt) will
have the format:
name: ageWe would like to store this information, and then allow the user to repeatedly search for a user by name. Each time, we will print out the age of the person with that name. First, we need a way to represent a person:
public class Person
{
private String name;
private int age;
public Person(String n, int a)
{
name = n;
age = a;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}Now, we will write a class with a main method that creates an ArrayList of type Person.
For each line in the file, we will create a new Person object and store it in our list. Then we
will let the user search the list by name:
import java.util.*;
import java.io.*;
public class PersonLookup
{
public static void main(String[] args)
{
ArrayList<Person> list = new ArrayList<Person>();
try
{
Scanner inFile = new Scanner(new File("info.txt"));
while (inFile.hasNext())
{
String line = inFile.nextLine();
String[] pieces = line.split(": ");
int age = Integer.parseInt(pieces[1]);
Person p = new Person(pieces[0], age);
list.add(p);
}
inFile.close();
}
catch (IOException ioe)
{
System.out.println("Trouble reading file");
}
Scanner s = new Scanner(System.in);
while (true)
{
System.out.print("Enter name (Enter to quit): ");
String name = s.nextLine();
if (name.length() == 0) break;
for (Person p : list)
{
if (p.getName().equals(name))
{
System.out.println(p.getAge());
}
}
}
}
}