The ArrayList Data Structure Standard Arrays at High Speed! More Safety, More Efficient, and Less Overhead! The Java ArrayList Class Java provides an ArrayList class to make it easier to work with arrays. An ArrayList is a one-dimensional array. There is a lot of overhead code to set up a standard array, fill it, track its logical size, and manipulate values in the array. An ArrayList make these operations easier. However, an ArrayList holds only objects, not primitive values like int, double, char or boolean. But in particular Java has the Integer and Double classes so you can place numbers in an ArrayList. Instantiating an ArrayList When you declare a standard array, you have to tell Java a fixed number of memory locations that you want the array to contain. During the run of a program, this cannot be changed unless you create a new standard array and copy all of the elements to it. This would be awkward to do and implement in every program that uses standard arrays. When you declare an ArrayList, you don’t have to tell Java how much storage space you need. The ArrayList will be created for a beginning amount and then it will automatically resize itself when it becomes full and more elements need to be added. Instantiating an ArrayList Declaring and instantiating a standard array: double [ ] nums = new double [20]; Declaring and instantiating an ArrayList: ArrayList <Double> nums = new ArrayList <Double> ( ); No square bracket [ ] notation is used for an ArrayList. Note the use of the templating angle brackets < and > that enclose the type of object to be placed in the array. Instantiating an ArrayList Declaring and instantiating an ArrayList of other types: ArrayList <Integer> nums = new ArrayList <Integer> ( ); ArrayList <String> names = new ArrayList <String> ( ); ArrayList <Student> students = new ArrayList <Student> ( ); ArrayList <Shape> shapes = new ArrayList <Shape> ( ); The ArrayList API says that all of the above ArrayLists will be constructed with an initial capacity of ten. Note the empty ( ) parentheses at the end of the constructor call. Don’t forget to include these. Instantiating an ArrayList You can declare and instantiate an ArrayList with an initial capacity of a certain size if you know approximately how many elements you will place in the ArrayList. The only real reason to do this is to keep the ArrayList from automatically resizing itself over and over again until all of the elements have been added to the ArrayList. However, this is not particularly inefficient for today’s computers unless you need to store many elements. For example, if you know you will have 1000 random integers in an ArrayList, you could use: ArrayList <Integer> nums = new ArrayList <Integer> (1000); Raw or Generic ArrayList? When you instantiate an ArrayList as you have just seen, we call it a generic ArrayList, because the programmer must specify the element type for the list as in … ArrayList <String> names = new ArrayList <String> ( ); Making a generic ArrayList with templating became available beginning with Java 1.5 and higher. Prior to that, programmers could only make a raw ArrayList, where you could put all kinds of objects in the same ArrayList, but care had to be taken to make sure only one kind of object was placed in a list. You can still declare and instantiate a raw ArrayList, like the following, but most compilers will “complain” and at least give you a warning if you are using Java 1.5 or higher. (some people refer to Java 1.5 as Java 5) ArrayList names = new ArrayList ( ); Advantages of ArrayList Operations are much much easier and less complex for: • traversing an ArrayList (accessing each element to print or perform an operation on it) • insertions anywhere in the ArrayList • removals anywhere in the ArrayList • searching an ArrayList An ArrayList tracks its own logical size and grows or shrinks automatically depending on the number of elements it has. ArrayList Differences • Instead of using [] to manipulate elements, methods are called to perform operations. • An ArrayList tracks its logical size and physical size. We don’t necessarily know what the physical size is and we don’t need to, because if more memory locations are needed then it will automatically resize itself. It is helpful to be able to access the logical size of an ArrayList when performing certain operations. The size() method is used to get the number of elements in the list. The logical size is 0 when an ArrayList is constructed and its logical size is automatically adjusted when an element is added or deleted. • An ArrayList does have indices and the positions of the elements range from index 0 to index logical size - 1. java.util.ArrayList The ArrayList class is part of the java.util package. So it is necessary to import this class by including: import java.util.ArrayList; The ArrayList class implements the List interface. That means that the ArrayList class must have all of the methods that are defined in the List interface. You will learn more about interfaces very soon, but we want to make you familiar with this fact now. The formal way to state this fact for the ArrayList class is: class java.util.ArrayList<E> implements java.util.List<E> The E in <E> simply stands for any kind of object or class name. Declaring Variables of type List Declaring and instantiating an ArrayList where the variable is of type List interface is the preferred way to go for many programmers. As you gain more experience programming you will understand why. Don’t worry about that for now. Here is the alternate way to declare and instantiate the ArrayList named students using the List interface: List <Student> students = new ArrayList < Student > ( ); Compare this to the previous way: ArrayList <Student> students = new ArrayList < Student > ( ); The java.util.List<E> interface An interface tells you the method signatures of the methods that classes that implement the interface must have. Here is what part of Java’s List interface looks like: public interface List { public int size ( ); public boolean add (E obj); public void add (int index, E obj); public E get (int index); public E set (int index, E obj); public E remove (int index); ……. } ArrayList and LinkedList use the List Interface A second class named the LinkedList class also implements the List interface. Since both of these classes have the same methods (but different code for them), we could choose to use the following declaration: List < Student > students = new LinkedList < Student > ( ); instead of … List <Student> students = new ArrayList < Student > ( ); This is one of the advantages of declaring variables of type List, because we don’t need to change any of the code in the program … only where students is declared and instantiated if we want to have a different kind of list. Some of the code in the LinkedList class is more efficient that the ArrayList class, because the LinkedList class is not based on a standard array but a different kind of list. You will learn about that if you take Advanced Computer Programming. Declaring Variables of type List Also, if we declare the variable shapes to be of type List <Shape>, then if the Shape is the parent of several classes like Circle, Rectangle, and Triangle, then we can hold all of those kinds of objects in the same list. This can be a real advantage. Now you are starting to learn about inheritance! List <Shape> shapes = new ArrayList <Shape> ( ); The ArrayList Subset of Methods There are many methods in the ArrayList class if you look up its API on line. However, we only want to work with a few methods of the ArrayList class … those in particular that you are expected to know for the AP Exam. You might not receive full credit on a free response coding question if you try to use methods other than the ones specified by the College Board. The specified methods and what they do are listed on the next slide. The ArrayList Subset of Methods ArrayList method What the Operation Does int size ( ) returns the logical size of the list boolean add (E obj) appends the object obj to the end of the list and returns true if successful (the fact that it returns true may be helpful sometimes) void add (int index, E obj) inserts the object obj at position index where index fulfills the expression 0 ≤ index ≤ size. If index is out of bounds in the range of index < 0 || index > size(), then Java throws an IndexOutOfBoundsException. Once obj is inserted, then the elements at position index and higher are moved to the right so that 1 is added to their indices and then the logical size is adjusted. Note: if there are 3 elements in the list at indices 0, 1, and 2, then obj can be added at index 3 without an out of bounds error E get (int index) returns the element at position index in the list E set (int index, E obj) replaces the element at position index with obj and returns the element formerly at the specified position E remove (int index) removes the element from position index in the list and then moves all elements at position index + 1 and higher to the left … subtracting 1 from their indices and then adjusting the logical size. The element formerly at the specified position is returned Wrapper Classes The Integer and Double classes are called wrapper classes, because they are used to “wrap up” primitive int and double values as objects so they can be put in an ArrayList or other kind of data structure. We used the Integer and Double classes earlier this year when we used … Integer.parseInt() and Double.parseDouble() to get the values from JTextFields or InputDialog boxes. Now let’s look a little closer at the Integer and Double classes see how to wrap up an int or double as an object. Wrapping & Unwrapping ints You don’t need to know the parseInt() method for the AP Exam, but you do need to know how to use the following methods of the Integer class: The constructor that has one parameter that is an int. If you want to wrap up an int, like 345, as an Integer object, then you would use the constructor to wrap it up: Integer intObj = new Integer(345); You have now wrapped up the int 345 and made it an Integer object and the variable intObj refers to that object! To unwrap the Integer object intObj and get the int value 345 out of it and store it in the int variable x, then you have to call the intValue() method … int x = intObj.intValue(); Wrapping & Adding Integers For the ArrayList … ArrayList <Integer> nums = new ArrayList <Integer> ( ); if we want to place the values 5, 10, and 15 in nums, in that order, we would wrap them up and add them as follows: Integer intObj1 = new Integer(5); nums.add(intObj1); // adds to the end of the list Integer intObj2 = new Integer(10); nums.add(intObj2); // adds to the end of the list You can also combine the lines by using … nums.add(new Integer(15)); // adds to the end of the list Autoboxing Integers Prior to Java 1.5, with a raw ArrayList, you had to wrap up int values. However, with the advent of Java 1.5 autoboxing became available. Here is the same code with autoboxing: ArrayList <Integer> nums = new ArrayList <Integer> ( ); nums.add(5); // autoboxing 5 and adding it nums.add(10); // autoboxing 10 and adding it nums.add(15); // autoboxing 15 and adding it However, the College Board still wants you to know how to wrap up int values. Unboxing Integers Prior to Java 1.5 with a raw ArrayList, you had to unwrap int values before using them. However, with the advent of Java 1.5 unboxing became available. Here is the code with unboxing: int x = nums.get(0); // get Integer at index 0 & unwrap using unboxing int y = nums.get(1); // get Integer at index 1 & unwrap using unboxing int z = nums.get(2); // get Integer at index 2 & unwrap using unboxing Here intValue() is called automatically by Java to unwrap the Integer object returned by get(i) so it can be stored in x, y, or z. You don’t have to call intValue() to unwrap because of unboxing! However, the College Board still wants you to know how to unwrap Integer objects. Wrapping & Unwrapping doubles You don’t need to know the parseDouble() method for the AP Exam, but you do need to know how to use the following methods of the Double class: The constructor that has one parameter that is a double. If you want to wrap up a double, like 12.3, as a Double object, then you would use the constructor to wrap it up: Double floatObj = new Double(12.3); You have now wrapped up the double 12.3 and made it a Double object and the variable floatObj refers to that object! To unwrap the Double object floatObj and get the double value 12.3 out of it and store it in the double variable d, then you have to call the doubleValue() method … double d = floatObj.doubleValue(); Wrapping & Adding Doubles For the ArrayList … ArrayList <Double> floats = new ArrayList <Double> ( ); if we want to place the values 5.5, 6.6, and 7.7 in floats, in that order, we would wrap them up and add them as follows: Double floatObj1 = new Double (5.5); floats.add(floatObj1); // adds to the end of the list Double floatObj2 = new Double (6.6); floats.add(floatObj2 ); // adds to the end of the list You can also combine the lines by using … floats.add(new Double (7.7)); // adds to the end of the list Autoboxing Doubles Prior to Java 1.5, with a raw ArrayList, you had to wrap up double values. However, with the advent of Java 1.5 autoboxing became available. Here is the same code with autoboxing: ArrayList <Double> floats = new ArrayList < Double > ( ); floats.add(5.5); // autoboxing 5.5 and adding it floats.add(6.6); // autoboxing 6.6 and adding it floats.add(7.7); // autoboxing 7.7 and adding it However, the College Board still wants you to know how to wrap up double values. Unboxing Doubles Prior to Java 1.5 with a raw ArrayList, you had to unwrap double values before using them. However, with the advent of Java 1.5 unboxing became available. Here is the code with unboxing: double b = floats.get(0); // get Double at index 0 & unwrap using unboxing double c = floats.get(1); // get Double at index 1 & unwrap using unboxing double d = floats.get(2); // get Double at index 2 & unwrap using unboxing Here doubleValue() is called automatically by Java to unwrap the Double object returned by get(i) so it can be stored in b, c, or d. You don’t have to call doubleValue() to unwrap because of unboxing! However, the College Board still wants you to know how to unwrap Integer objects. Adding Elements to an ArrayList - add(obj) The following code stores the first 100 multiples of 3 in nums in order: ArrayList <Integer> nums = new ArrayList <Integer> ( ); int value = 3; for (int i = 0; i < 100; i++) { nums.add(value); // adds at the end of the list value += 3; } Note: if nums was a standard array, we would use … nums [i] = value; in place of nums.add(value); Getting Elements from an ArrayList - get(i) The following code prints the values stored in nums with 10 values per line with a field width of 5: for (int i = 0; i < nums.size(); i++) { if ( (i + 1) % 10 == 0 ) System.out.printf( “%5d%n”, nums.get(i) ); else System.out.printf( “%5d”, nums.get(i) ); } Note: if nums was a standard array, we would use … System.out.printf( “%5d”, nums[i] ); Getting Elements from an ArrayList - get(i) To obtain the first element in an ArrayList always use … nums.get(0); To obtain the last element in an ArrayList always use … nums.get(nums.size() - 1); Note that since there are num.size() elements in the ArrayList, then the index of the first element is 0 and the index of the last element is nums.size() - 1. Removing Elements from a Position - remove(i) The following code removes and prints all of the multiples of 6 from nums in a field width of 5: int i = 0; while ( i < nums.size() ) { if ( nums.get(i) % 6 == 0 ) { int x = nums.remove(i) ; System.out.printf( “%5d”, x ); // don’t increment i because elements are shifted down } else // if not evenly divisible by 6 increment i i++; } Removing Elements from a Position - remove(i) The following code removes and prints all of the multiples of 6 from nums in a field width of 5 using a for loop: for (int i = 0; i < nums.size() ; i++) { if ( nums.get(i) % 6 == 0 ) { int x = nums.remove(i) ; System.out.printf( “%5d”, x ); i--; // to cancel the effect of i++ in loop header } } Removing Elements from a Position - remove(i) To delete the first element in an ArrayList always use … nums.remove(0); To delete the last element in an ArrayList always use … nums. remove(nums.size() - 1); Again, since there are num.size() elements in the ArrayList, then the index of the first element is 0 and the index of the last element is nums.size() - 1. Adding Elements at a Position - add(i, obj) The following code adds the integer 3 at the first of the list named nums using the add(i, obj) method, where the list initially contains 6, 9, 12. nums.add (0, 3); // add 3 at index 0. The list now contains: 3 6 9 12 The following code adds the integer 15 at the end of the list no matter how many elements there are using the add(i, obj) method. nums.add (nums.size() , 15); // add 15 after the last element Since nums.size() is 4 before adding 15, then 15 is added at index 4. Obviously 3, 6, 9, &12 are in indices 0, 1, 2, & 3. The list now contains: 3 6 9 12 15 Replacing Elements at a Position - set(i, obj) Assume nums contains: 3 6 9 12 15 The following code replaces the element at index 2 with the value 10 using the set(i, obj) method. It returns the replaced element and prints it out. int x = nums.set (2, 10); // replace 9 at index 2 with 10. System.out.println(“The replaced value was ” + x); The list now contains: 3 6 10 12 15 Replacing the last value in the ArrayList … int x = nums.set (nums.size() - 1, 20); The list now contains: 3 6 10 12 20