ArrayLists

  • Core Java: Volume I—Fundamentals

    • Chapters 9.1 and 9.2

List Interface

We're going to dive into interfaces in a couple sections, so we'll keep the description of an interface short and sweet. We'll spend the bulk of our time on a concrete implementation of the List interface.

An interface is a defined set of behaviors that any implementing classes must support. The List interface defines these behaviors for classes that store a sequence of elements. That definition looks like this.

  • Elements can be inserted or accessed by their position in the list using zero-based indexes.

  • A list may contain duplicate elements.

  • All lists take on (by extension, which we'll cover later) the functionality of a Collection.

  • In addition to these inherited methods, the List interface defines the following methods of its own.

The List interface provides a host of methods that concrete classes must implement.

ArrayList

There are four classes that implement the List interface.

  • ArrayList

  • LinkedList

  • Vector

  • Stack

We're going to focus on the ArrayList implementation. An ArrayList is a built-in class in the Java programming language that functions much like an array.

It resizes itself automatically when more elements are added or inserted, while also maintaining order. The same is true of removals; order is maintained.

Declaration

We can declare an ArrayList like we would any other variable: with a data type and a name. The data type is, of course, ArrayList. However, like an array, we also need to specify the data type of the elements that will be stored in our ArrayList.

ArrayList<Integer> numbers;
ArrayList<Double> reals;
ArrayList<String> words;

We can't store primitive values in an ArrayList, so we need to use wrapper classes.

Wrapper Classes

There are wrapper classes for each of the primitive data types we might want to store in an ArrayList.

  • Character

  • Boolean

  • Byte

  • Short

  • Integer

  • Long

  • Float

  • Double

These classes come with some methods that you may or may not find useful. You can check them out in the JDK Documentation. Just search for the class you need.

For the purposes of ArrayLists, though, we only care that these classes can represent primitive data types in object form.

Initialization

To initialize an ArrayList, we need to use the new operator. We're calling a constructor similar to what we've done with Strings and Scanners, so it looks like a method call (because it is).

ArrayList<Integer> numbers;
numbers = new ArrayList<Integer>();

// or in one line

ArrayList<Double> reals = new ArrayList<Double>();

// alternatively, newer versions of the JDK allow for the omission of the
// right-hand type parameter

ArrayList<Integer> numbers = new ArrayList<>();    // Integer is implied

The syntax is a little odd because the constructor's parentheses come after the angled brackets indicated the data type.

Getting

With arrays, we used bracket notation to access values in the array. With ArrayLists, we use the built-in get method. We pass in an index just like we did with arrays.

ArrayList<Integer> evens = new ArrayList<>();

// assume evens is populated with all even numbers
// in the range [2, 100) in increasing order

int a = evens.get(0);
int b = evens.get(1);
int c = evens.get(2);

// a, b, and c hold 2, 4, and 6, respectively

Adding, Inserting, and Setting

Like get, there are built-in methods to add, insert, and set elements. When we add an element to a list, we're appending it to the end. Inserting elements means we're plugging them in somewhere that is not the end of the list. Setting means we're overwriting one element with another.

Adding and Inserting

The confusing part, though, is that we use the add method to achieve both adding and inserting.

  • add(Object obj)

  • add(int index, Object obj)

To append an element, we pass only the element to be added to the add method.

ArrayList<String> fruits = new ArrayList<>();

fruits.add("apple");
fruits.add("banana");
fruits.add("cherry");

// fruits now contains: "apple", "banana", "cherry"

Suppose we have that same list we just populated. Now, we want to insert blueberry between banana and cherry. We use the add method, but we give it an index, too.

fruits.add(2, "blueberry");

// now fruits contains: "apple", "banana", "blueberry", "cherry"

Make sure you know what you're trying to do and use add appropriately!

Setting

There's another way to add an element to a list. This time, though, we'll be overwriting one element with another. To do this, we use the set method.

  • set(int index, Object obj)

Using this method will overwrite the element at index with obj. Remember our list of fruits? We're going to overwrite banana with apricot.

// fruits contains: apple, banana, blueberry, cherry

fruits.set(1, "apricot");    // overwrite index 1 with "apricot"

// now fruits contains: "apple", "apricot", "blueberry", "cherry"

Autoboxing and Unboxing

Java takes care of conversions between primitive data types and their object wrapper equivalents. This is called autoboxing (converting from a primitive to a wrapper class) and unboxing (converting from a wrapper class to a primitive).

An example will probably do this explanation the most justice.

ArrayList<Integer> numbers = new ArrayList<>();

int x = 7;
numbers.add(x);            // autoboxing! x is converted to an Integer

int y = numbers.get(0);    // unboxing! returned value is converted to an int

Removing

Removing is pretty straightforward, but there are two ways to do it.

  • remove(int index)

  • remove(Object obj)

If we know the index of the element we want to remove, then we'll use the remove method that accepts an index as a parameter.

ArrayList<String> words = new ArrayList<>();

words.add("apple");
words.add("bark");
words.add("caterpillar");

// now let's remove the word at index 1 (i.e., "bark")

String removed = words.remove(1);

// removed now equals "bark"
// words now contains "apple", "caterpillar"

As you saw, this particular remove method returns the element it removed.

We can also search for a specific element and remove that. We pass an object to the remove method and, if it exists in the list, the first occurrence will be removed.

ArrayList<String> words = new ArrayList<>();

words.add("apple");
words.add("bark");
words.add("caterpillar");
words.add("dog");

// now let's remove the word "caterpillar"

boolean removed = words.remove("caterpillar");

// removed is true
// words now contains "apple", "bark", "dog"

This time, the remove methods returns true if the element was found and removed (or false if it was not).

Iterating

Just like arrays, you'll find the need to traverse the contents of your ArrayLists. There are a number of ways you can do this.

Using a Traditional for Loop

To use a traditional for loop, we need to know how many elements are in the list. Arrays had a length property. ArrayLists have a size method.

ArrayList<Integer> odds = new ArrayList<>();

// populate list with odd numbers

for (int i = 0; i < odds.size(); i++) {
    int num = odds.get(i);

    // do something with num
}

Using an Enhanced for Loop

You can use an enhanced for loop in the same way you did with arrays.

ArrayList<Integer> odds = new ArrayList<>();

// populate list with odd numbers

for (int num : odds) {
    // do something with num
}

Using a ListIterator

This one's new and it's specific to ArrayLists (or classes that implement the List interface). Once we get an instance of our ListIterator, we can use it to traverse the ArrayList in either direction.

ArrayList<String> words = new ArrayList<>();

words.add("always");
words.add("brother");
words.add("color");
words.add("dangerous");

ListIterator iter = words.listIterator();

There are hasNext and hasPrevious methods that let us move forward and backward along the list without going too far.

while (iter.hasNext()) {
    String word = iter.next();
    System.out.println(word);
}

// prints:
//   always
//   brother
//   color
//   dangerous

while (iter.hasPrevious()) {
    String word = iter.previous();
    System.out.println(word);
}

// prints:
//   dangerous
//   color
//   brother
//   always

Check out the documentation for all of the ListIterator capabilities and methods.

Last updated

Was this helpful?