In previous lessons, we explored the Java Array
data structure. In this lesson we'll walk through the Java ArrayList data structure, and review the differences and similarities between Java's Array
and ArrayList
. After that, we'll practice creating, accessing, and manipulating our own custom array lists.
When we learned about Arrays, we briefly covered the differences between the Java Array
and ArrayList
data structures. Due to how often beginning Java developers mistakenly mix them up, let's review their similarities and differences one more time:
Java includes both an Array
and an ArrayList
class. They're each "collections of multiple items", so to speak, but they're also very different.
An ArrayList
can fluctuate in size as things are added or removed. A single ArrayList
is also capable of holding variety of different types of objects.
An Array
is stricter. Their length/size may not fluctuate. All items within it must be of the same type (such as String
, or Integer
).
This lesson will explore the ArrayList
data structure. To review the Array
structure, see Data Structures: Arrays.
There are several steps to create a Java ArrayList
. We'll walk through each together:
ArrayList
and List
classes from the java.util
package.To create an array of integers in the REPL, for instance, we simply had to do this:
> Integer[] primeNumbers = { 2, 3, 5, 7, 11 };
java.lang.Integer[] primeNumbers = [2, 3, 5, 7, 11]
However, to create an array list we need to import the ArrayList
class from Java's built-in java.util
package first. This is very similar to the manner we imported code from the Console
in the Importing Code lesson.
To do this, we include the following lines at the top of any .java
files that use array lists. Or, when working in the REPL, we can type these same lines and hit enter. The REPL will load the necessary classes from the java.util
package.
import java.util.List;
import java.util.ArrayList;
Data in Java ArrayLists isn't required to be one single type like it is in an Array
. However, if your ArrayList's data will be a single type, it is best practice to declare that type in angle brackets, like so:
import java.util.List;
import java.util.ArrayList;
List<String> myStringList = new ArrayList<String>();
List<Integer> myIntegerList = new ArrayList<Integer>();
List<Boolean> myBooleanList = new ArrayList<Boolean>();
The String
, Integer
and Boolean
keywords we see in the angle brackets <>
above are known as generics. Generics were introduced in 2004 as part of JDK 5.0 in order to allow the Java compiler to catch and alert us of more errors while compiling code, before we ever run our programs. Generic types tell Java what kind of object this data structure can hold.
The generic type can be any object type. Object types are simply data types that are objects. They're easy to spot because their first letter is capitalized. Since primitives are not objects, you'll have to use their object type wrapper class when creating an ArrayList instead (ie: use Integer
instead of int
. Integer
is an object type, and int
is a primitive).
It is generally a good idea to use the generic type for a couple reasons:
We'll walk through how to store a variety of differing data types in a single ArrayList
in the "Storing Varying Data Types in ArrayLists" section at the end of this lesson.
This should be second nature. After declaring the ArrayList and generic type, include a name. Like List<Boolean> myBooleanList
, or List<Integer> myIntegerList
.
ArrayList
using the constructor.Finally, after setting everything up we can create our ArrayList
using its constructor with the new
keyword, as seen in these examples:
import java.util.List;
import java.util.ArrayList;
List<String> myStringList = new ArrayList<String>();
List<Integer> myIntegerList = new ArrayList<Integer>();
List<Boolean> myBooleanList = new ArrayList<Boolean>();
The ArrayList
and its generic type in angle brackets should be included after the keyword new
. Additionally, we include a set of empty parentheses, even though they look a little odd after the closing angle bracket.
This is because the constructor used to create new instances of ArrayList
is also a type of method, and therefore requires a set of parenthesis.
Once we've successfully created an ArrayList
using the steps above, we can call the add()
method, and pass in the content we'd like to include in the ArrayList
as an argument:
> import java.util.List;
> import java.util.ArrayList;
> List<String> myList = new ArrayList<String>();
java.util.List<java.lang.String> myList = []
> myList.add("hello");
java.lang.Boolean res1 = true
> myList.add("world");
java.lang.Boolean res2 = true
> myList;
java.util.List<java.lang.String> myList = [hello, world]
In the code above create a new ArrayList
of the <String>
generic. Then, we call add()
twice to add two separate strings: "hello"
and "world"
. When we reference myList
again, we can see it now contains both strings.
Similar to JavaScript, items in an ArrayList
each have a unique index. The very first item has an index of 0, and each subsequent item has an index of 1, 2, 3, etc. We can access an item at a specific index using the get()
method:
> myList;
java.util.List<java.lang.String> myList = [hello, world]
> myList.get(0);
java.lang.String res3 = "hello"
> myList.get(1);
java.lang.String res4 = "world"
Additionally, we can access each individual item of an ArrayList
with a loop, just like we can with an Array
:
> myList;
java.util.List<java.lang.String> myList = [hello, world]
> for ( String word : myList ) { System.out.println(word); }
hello
world
As mentioned, it is possible to place objects of different types in the same ArrayList
. To do this, you declare the array list's generic as <Object>
, like so:
> List<Object> objectList = new ArrayList<Object>();
java.util.List<java.lang.Object> objectList = []
All objects inherit from a built-in Java class called Object
. This is why we can simply declare their type as Object
, because they are instances of the Object
class, too. We'll learn more about the concept of inheritance later, just know any object can use methods defined by the Object
class, or be stored in an Object
type variable.
Object
TypesHowever, if you declare Object
as the generic type you will no longer be able to use class-specific methods on the contents of the array list. By declaring everything in the ArrayList
as the more general Object
, you lose the ability to call methods meant for more specific classes like String
.
For example, a string saved as an Object
in an ArrayList
, like this....
> List<Object> objectList = new ArrayList<Object>();
java.util.List<java.lang.Object> objectList = []
> objectList.add("Hello");
java.lang.Boolean res1 = true;
...Can no longer have String
-specific methods like .toUpperCase()
called on it. You can still use methods defined by the Object
class, though, like toString()
, .equals()
and .getClass()
.
List
vs ArrayList
While following along with this lesson, you may have noticed something a little odd. When we create a new ArrayList
, it looks like this:
import java.util.List;
import java.util.ArrayList;
List<String> myStringList = new ArrayList<String>();
On the left-hand side of the =
we state List<String>
. Yet on the right-hand side we state new ArrayList<String>();
. One says List<String>
and the other says ArrayList<String>
! We also have to import both the java.util.List
package and the java.util.ArrayList
package! What gives?!
List
is the parent class of ArrayList
. ArrayList
is a specific type of List
. By declaring the ArrayList
as the more general List
parent class, but defining it as the more specific ArrayList
we have much more flexibility. In addition, declaring an ArrayList
as List
is considered to be best practice.
If we later needed to change our ArrayList
to a different type of list (we'll explore these other types later on), declaring our ArrayList
as the broader List
parent class would allow us to do this more easily.
We'll explore exactly why this works, when it comes in handy, and what other datatypes this applies to in future lessons when we discuss inheritance. For now, simply know that when we create an ArrayList
, we declare it as a List
on the left-hand side of the =
, and use the ArrayList
constructor on the right-hand side. Like this:
import java.util.List;
import java.util.ArrayList;
List<String> myStringList = new ArrayList<String>();
Package: A technique for organizing similar types of Java code. Including code built-in to the Java language. When we want to use functionality from a Java package, we can import it by including something like this: import java.util.ArrayList;
. In this instance, java.util
is the package, and ArrayList
is a specific class within that package.
Generic: Introduced in 2004 as part of JDK 5.0 in order to allow the Java compiler to catch and alert us of more errors while compiling code, before we ever run our programs. Generic types tell Java what kind of object a data structure can hold.
Object Type: Objects in Java inherit functionality from a built-in Object
class. Anything that is an object can be considered "Object type".