dynamic collections in Java
Create an array of 3 things you use a lot — your favorite games, apps, foods, whatever.
Write the Java code. Be ready to share.
What do we know about arrays?
index[0]?index[1]?What if I want to add one more thing?
Is it impossible or just inconvenient?
Did we actually change the array?
What if we wanted to insert an item into the array?
What would you need to do if you wanted to insert something in the middle?
Be specific. What steps would your code take?
We can add (though it is a bit of work), and with some more work we'd be able to insert an item into or delete an item from the array by shifting things around.
But the main problem is that we have to create a whole new array to hold the new items. We can't just change the size of the existing one. We didn't change the original array. We made a new one and copied everything into it.
That means:
Before
After
You know programmers are lazy. If something is annoying to do... we automate it. And you can bet we have automated all of this!
Introducing: the ArrayList
Java has a class that handles all of this work for us. Notice that "Array" in there, there's an array under the hood but we don't have to manage it!
Go back to the program we were working on.
We'll rewrite it using ArrayList.
The ArrayList object is always the same object. We don't have to replace the list — we just add to it. It updates its own internal array reference so we don't have to.
Normal operation
After growth — same object, new internal array
Like other objects, you must declare and initialize before use.
// Declaration only
ArrayList<String> myStuff;
// Declaration and Initialization
ArrayList<String> myStuff = new ArrayList<String>();
// Better — Java infers the type in the second <>
ArrayList<String> myStuff = new ArrayList<>();
ListIn this class you'll mostly see:
ArrayList<String> myStuff = new ArrayList<>();
In the real world, you'll often see:
List<String> myStuff = new ArrayList<>();
List is a more general type. Swapping implementations (ArrayList, LinkedList, Vector...) takes just one line.
List<String> myStuff = new Vector<>();
Let's fix it by initializing the ArrayList:
ArrayList myPoints = new ArrayList();
ArrayList<int> myPoints = new ArrayList<>();
int[] (an array of ints). We don't want a list of arrays — we want ints!ints.Lists store objects, not primitives. But Java has our back with object versions of every primitive type:
ArrayList<Integer> myPoints = new ArrayList<>();
Does it work now?!
ArrayList<Integer> myPoints = new ArrayList<>();
myPoints.add(3);
myPoints.add(2);
myPoints.add(5);
myPoints.add(1);
System.out.println(myPoints);
What do you think this will print?
I know you are all thinking:
"MrD, you just said ArrayLists can only store objects. But you just added ints to it!"
Java is doing behind-the-scenes work. This is called:
When Java needs an object, it wraps the int in an Integer "box". When it needs the value back, it unwraps it.
ArrayList<Integer> myPoints = new ArrayList<>();
myPoints.add(3);
myPoints.add(2);
myPoints.add(5);
myPoints.add(1);
System.out.println(myPoints.get(0) + 5); // unboxed automatically
System.out.println(myPoints);
ArrayList<Integer> myPoints = new ArrayList<>();
myPoints.add(3);
myPoints.add(2);
myPoints.add(5);
myPoints.add(1);
myPoints.set(2, 0); // index then value
System.out.println(myPoints.get(0) + 5); // unboxed automatically
System.out.println(myPoints);
What will the list look like?
Oops, we messed up with that 2:
myPoints.add(3);
myPoints.add(2);
myPoints.add(5);
myPoints.add(1);
myPoints.set(2, 0); // index then value
myPoints.remove(2); // removes item at index 2
System.out.println(myPoints.get(0) + 5); // unboxed automatically
What will the list look like?
If remove() is given an int, it treats it as an index. If it gets an Integer object, it removes the first matching value.
Java sees a number and assumes you mean an index… unless you explicitly cast:
myPoints.remove((Integer) 2);
myPoints.add(3);
myPoints.add(2);
myPoints.add(5);
myPoints.add(1);
myPoints.set(2, 0);
myPoints.remove((Integer) 2);
System.out.println(myPoints.get(0) + 5); // unboxed automatically
list.remove(2);
list.remove((Integer) 2);
myPoints.add(3);
myPoints.add(2);
myPoints.add(5);
myPoints.add(1);
myPoints.set(2, 0); // index then value
myPoints.remove((Integer) 2); // remove first 2
myPoints.add(4, 1); // insert 1 at index 4
System.out.println(myPoints.get(0) + 5); // unboxed automatically
We just got an error. I wanted to insert a 4 at index 1.
What happened? Why did the code fail?
When adding, you tell it where first, then what:
list.add(4);
list.add(1, 4); // index then value
What code will tell us how many items are in a list?
myPoints.size()myPoints.lengthmyPoints.length()myPoints.numItems()
"Java was built by many teams over many years and we, uh… didn't always coordinate.
Our bad. Just memorize it."
myPoints.add(3);
myPoints.add(2);
myPoints.add(5);
myPoints.add(1);
myPoints.set(2, 0); // index then value
myPoints.remove((Integer) 2); // remove first 2
myPoints.add(1, 4); // index then value
System.out.println(myPoints.get(0) + 5); // unboxed automatically
System.out.print(myPoints.size());
Which correctly creates an empty ArrayList of Strings?
ArrayList<String> list = new ArrayList<>();ArrayList<String> list;ArrayList<String> list = new ArrayList();ArrayList list = new ArrayList<String>();What is wrong with this code?
ArrayList<int> nums = new ArrayList<>();
So far we've stored Strings and numbers
but lists can store any object.
Let's work with something a little more interesting.
Each Grade stores a score and can tell us the letter grade.
public class Grade {
private double myGrade;
/** @param score numeric grade, 0.0–100.0 */
public Grade(double score) { /* code omitted */ }
/** @return numeric value 0–100 */
public double getGrade() { /* code omitted */ }
/** @return letter grade "A"–"F" */
public String getLetter() { /* code omitted */ }
}
Declare and initialize an ArrayList of Grades:
ArrayList<Grade> grades = new ArrayList<>();
Create a Grade of 100%:
new Grade(100)
Create a random Grade 0–100%:
new Grade(100 * Math.random())
Add that Grade to the list:
grades.add(new Grade(100 * Math.random()));
Add that 28 random Grades to the list:
That's up to you.
How can we print all of the grades? Not like this:
System.out.println(grades);
// [Grade@7d6f77cc, Grade@5aaa6d82, Grade@73a28541,
// Grade@6f75e721, Grade@69222c14, Grade@606d8acf,
// Grade@782830e, Grade@470e2030, Grade@3fb4f649 ...]
We need to use the Grade methods and our old friend: the for loop!
Open Grades Example →for ( int i = 0 ; ___ ; i++ ) {
System.out.println( grades.get(i).getGrade() );
}
What condition should we use?
Hint: how do we know how many elements are in the list?
for ( ___ g : ___ ) {
System.out.println( g.getLetter() );
}
Why do ArrayLists exist if we already have arrays?
What problems do they solve? What trade-offs do they make?