Unlike arrays which are built into Java the language and are used with special syntax such as array initializers like new int[] { 1, 2, 3 } and array access expressions like nums[0], and even unlike the String class which gets some special support from the language, ArrayList is a class that we could write ourselves if it didnβt exist. In other words ArrayList is a new class abstraction that hides some of the messy details of using an array to represent a collection of values when we want to be able to change the number of values in the collection over time.
Thus to learn how to use it we just need to learn about its public APIβthe constructors and methods the class provides. The whole API is quite large and is fully documented in the classβs Javadocs. But for our purposes we only need to know a handful of methods which weβll cover in this chapter.
An ArrayList is often called just a list. Prior to 2020 the AP CSA curriculum included interfaces which are somewhat like classes and the interface List was often used to declare a variable that would refer to an ArrayList. Interfaces are no longer on the exam, but if you see List being used in an old exam question just assume itβs an ArrayList. You will also see references to List if you read the ArrayList Javadocs.
An ArrayList will always use less memory than an array.
No, The underlying array in an ArrayList is actually usually bigger than the number of values stored in the ArrayList. It is expanded as needed by making a new bigger array, usually twice the size of the old array, and copying values from the old array into the new one.
An ArrayList can store objects, but arrays can only store primitive types.
No, arrays can store both primitive and reference types while ArrayLists can only store reference types. Weβll see in the next section how to use wrapper classes to make ArrayList that hold int and double values.
An ArrayList has faster access to the last element than an array.
No, an ArrayList is implemented using an array so the time to access an element of an array list is essentially the same same as the time to access the element of the underlying array.
An ArrayList resizes itself as necessary as items are added, but an array does not.
Recall from SubsectionΒ 3.2.2Β Packages that classes in Java are organized into packages. The standard Java classes we have used until now, String and Math, are in the special package java.lang whose classes are always available in any Java program so weβve been able to refer to them without doing anything special.
ArrayList, on the other hand, is in a different package, called java.util. That means that if we want to use ArrayList in a program we need to either import it or (much more rarely) refer to it by its full name which includes the package as a prefix: java.util.ArrayList. But rather than type that out all the time weβll almost always use an import statement.
Import statements have to come before the class definition in a Java source file and serve to tell Java which class we mean when we use a short name like ArrayList. To import just one class we use a single import of the fully-qualified name of the class like this:
// Import everything in java.util including ArrayList
import java.util.*;
This import statement will also cause, ArrayList to refer java.util.ArrayList. But many other names of classes defined in the java.util package will also be available whether you use them or not. (One that you have probably used by now is Scanner which can be used to read input a user types at the command line.) Using wildcard imports can cause conflicts if you import all the classes from two different packages and they have class names in common but usually thatβs not a problem, at least with packages that are part of Java itself.
Just like when we declare an array and have to specify what kind of array it is in terms of what kind of values it can hold (e.g. String[] vs int[]), when we declare an ArrayList we also need to specify what kind of values it will hold. The syntax is slightly different from the array declaration syntax and is actually an example of a feature of Java called generic types. Generic types are not otherwise covered in the AP curriculum but are an important part of real-world Java programming.
To declare an ArrayList variable we write the type of the variable as ArrayList<Type> name where Type, called a type parameter, is the type of the objects we want to store in the ArrayList.
If you look at the ArrayList Javadocs youβll see the class listed as ArrayList<E>. The E is the name for the type parameter and tells us that we need to provide an actual type like String when we declare an ArrayList. If you look at the Javadocs for ArrayList methods (or at the AP CSA Java Quick Reference Sheet) youβll see the E again as the type of method parameters and return types. That means that those methods take parameters and return values of whatever specific type you specified when you declared a particular ArrayList.
For example the add method has the signature boolean add(E e) which means if youβve declared an ArrayList<String> then, for that ArrayList, itβs as if the add method had the signature boolean add(String e) which makes sure that no code can add anything other than a String to that ArrayList.
Similarly the get method has the signature E get(int index) which means that the values returned by get from the same ArrayList will be of type String so we can safely use String methods on them.
It is legal to declare a variable to just be of type ArrayList, with no type parameter, but youβll get a warning from the compiler about raw types. That raw types are allowed at all is due to the history of how generic types were added to Java and a desire to add the feature to the language without breaking older Java code. These days you should always specify the type of objects you intend to store in an ArrayList as it allows the compiler to find errors that would otherwise not be detected until run time.
As with other reference types, declaring a ArrayList variable doesnβt actually create an object; it just creates a variable that can hold a reference to an ArrayList or the special reference null.
To actually create a ArrayList we must invoke a constructor. The main ArrayList constructor takes no arguments and returns an empty ArrayList. There are two ways to invoke the constructor: new ArrayList<String>() with a type parameter or new ArrayList<>() without the type parameter. The latter way is generally preferred; in most contexts, such as when initializing a variable declaration Java will infer the necessary type parameter so you donβt have to specify it twice:
Another useful constructor, though not officially part of the AP curriculum, is the copy constructor that takes another ArrayList and makes a new ArrayList containing the same values:
ArrayList<String> copyOfStrings = new ArrayList<>(strings);
The type parameter of an ArrayList can be any reference type including classes that we write, such as the Student or Person, classes that other programmers have written such as Turtle, or even arrays like int[] though it is a bit odd to mix ArrayLists and arrays that way.
However the type parameter cannot be a primitive type so we cannot make an ArrayList<int> or ArrayList<double>. In the next section weβll discuss how to use wrapper classes to work around that limitation.
// An ArrayList of Students:
ArrayList<Student> roster = new ArrayList<>();
// An ArrayList of Turtles:
ArrayList<Turtle> turtles = new ArrayList<>();
// An ArrayList of arrays of int
ArrayList<int[]> arrays = new ArrayList<>();
Activity10.1.3.
The code below uses the size method which will discuss in a moment to show how many elements are in an ArrayList. Notice that a newly constructed ArrayList is empty and thus has a size of 0.
The following code also has a bug that leads to a NullPointerException. Change the list2 declaration so that it creates a new ArrayList to remove the NullPointerException.
The following are the ArrayList methods that you need to know for the AP CSA exam. These are included on the AP CSA Java Quick Reference Sheet that you will receive during the exam so you do not need to memorize them. As we discussed above the E in the method headers is a placeholder for the specific type used when we declare an specific ArrayList.
E get(int index) returns the item in the list at the position index. The index must be a valid index into the list. As with array and String indexes, index of the first item in an ArrayList is 0 and the last valid index is one less than the size() of the list.
E remove(int index) removes the item at the index index and shifts remaining items to the left (to a lower index), returning the removed item. The index argument must be a valid index into the list.
void add(int index, E obj) moves any objects at positions greater than or equal to index to the right (to a higher indexes) and inserts obj at the position index. The index argument must be a valid index or exactly the size() of the list in which case the item is added at the end of the list.
Java is unfortunately all over the map when it comes to how to get the number of items in different data structures. With an array, we use the lengthfield to get the number of items in the array while with a String we use the length()method to get the number of characters in the String. And with an ArrayList we use the size() method to get the number of items in the list. Mixing these up is a common mistake for new Java programmers. However you will not be penalized if you mix them up on the AP exam.
You can get the object at an index using obj = listName.get(index) and set the object at an index using listName.set(index,obj). Both methods require that the index argument refer to an existing element of the list, i.e. the index must be greater than or equal to 0 and less than the size() of the list.
Try to guess what the code below will print before running it. Can you get the last element in the nameList to print it out? Can you set the first element in the list to your name and print out the list?
set changes the value and the first index is 0 not 1.
["Anaya", "Sarah", "Sharrie"]
add at index 1 adds the new value at that index but moves right any existing values.
["Anaya", "Sarah", "Destini", "Sharrie"]
The list is first ["Anaya", "Layla", "Sharrie"] and then changes to ["Anaya", Destini", "Sharrie"] and then to ["Anaya", "Sarah", "Destini", "Sharrie"]
Remember that there are two different add methods in the ArrayList class. The add(obj) method adds the passed object to the end of the list while add(index,obj) method adds the passed object at the passed index, but first moves over any existing values to higher indices to make room for the new object.
Subsection10.1.5When to use an array vs an ArrayList?
Suppose we need to store a collection of values. How do we decide when to use an array vs an ArrayList? Often the choice is obvious: if we want to store a collection of values that can grow or shrink we definitely want to use an ArrayList.
And even if we donβt think we need to grow or shrink our collection an ArrayList is often still a good choice. While you need to know how to use arrays to be a competent Java programmer (and to do well on the AP exam) in day-to-day programming you can get pretty far just using ArrayList when you need a collection of values.
That said, arrays have some advantages: precisely because they are relatively limited, they are also very efficient. And because they have special syntax in the language they can be easier to use.
Piece[][] board = new Piece[8][8];
board[0][0] = new Piece("black", "rook");
Simply constructing the array allocates memory to hold sixty-four Piece objects and then we can set an element with the simple array access expression board[0][0].
ArrayList<ArrayList<Piece>> board = new ArrayList<>();
// Need to make all the nested ArrayLists and fill them out
for (int i = 0; i < 8; i++) {
ArrayList<Piece> row = new ArrayList<>();
for (int j = 0; j < 8; j++) {
row.add(null);
}
board.add(row);
}
// To set an particular square we get the row and then set the column.
board.get(0).set(0, new Piece("black", "rook"));
Pretty much everything about the ArrayList version, from the type of the variable to the code we have to write to initialize things and then the code to access elements of the nested ArrayLists is way more complicated with no real benefit since the size of the chess board is never going to change.
The other place arrays have some advantages are in dealing with primitive values since an ArrayList can really only hold reference types. Weβll look at that issue in more detail in the next section.
Here is a comparison of how to access and change elements in an array vs an ArrayList. Note that ArrayLists have a method size() instead of a length property, and ArrayLists use get/set methods instead of the index operator ([]).
Note that the ArrayList methods add and remove do not have a simple equivalent in arrays because they change the number of elements in the list and may shift the positions of other elements.
Here is a comparison handout of the basic operations to access one- and two-dimensional arrays, ArrayLists, and Strings made by AP CSA teacher Sam Procopio of Bishop Blanchet High School.
Rewrite the following code that uses an array to use an ArrayList instead. In the comments write why you think an ArrayList is a better data structure to use than an array for this problem.
Although it is not on the AP exam, you can convert an array to a List using the static method asList from the Arrays helper class: Arrays.asList(arrayname). Note that ArrayList has a toString method that is automatically called to print the list in a nice format.
(AP 4.8.A.4) The ArrayList class is part of the java.util package. An import statement can be used to make this class available for use in the program.(import java.util.ArrayList or java.util.*).
(AP 4.8.A.1) An ArrayList object is mutable in size and contains object references. (Mutable means that it can change by adding and removing items from it.
(AP 4.8.A.3) Java allows the generic type ArrayList<E>, where the generic type E specifies the type of the elements. (Without it, the type will be Object). When ArrayList<E> is specified, the types of the reference parameters and return type when using its methods are type E.
(AP 4.8.A.3) ArrayList<E> is preferred over ArrayList (which creates an list of type Object). For example, ArrayList<String> names = new ArrayList<String>(); allows the compiler to find errors that would otherwise be found at run time.
ArrayLists cannot hold primitive types like int or double, so you must use the wrapper classes Integer or Double to put numerical values into an ArrayList. However autoboxing usually takes care of that for you.
void add(int index, E obj) : Inserts obj at position index (0 <= index <= size), moving elements at position index and higher to the right (adds 1 to their indices) and adds 1 to size
remove(int index) β Removes element from position index, moving elements at position index + 1 and higher to the left (subtracts 1 from their indices) and subtracts 1 from size; returns the element formerly at position index