Optimized Implementation
So with that context we can update the simple implementation as follows.
Note the use of IndexOutOfBoundsException
. It is an unchecked exception that
comes with Java specifically for when an index is out of bounds.1
class GrowableIntArray {
private int[] data;
// We need a different variable to store the size
// since the array's size will different than we want.
private int size;
GrowableIntArray() {
this.data = new int[0];
this.size = 0;
}
int get(int index) {
// Now that we manage the size, we need to do
// "bounds checks" ourselves
if (index >= size) {
throw new IndexOutOfBoundsException(index);
}
return this.data[index];
}
void set(int index, int value) {
// For setting as well
if (index >= size) {
throw new IndexOutOfBoundsException(index);
}
this.data[index] = value;
}
int size() {
// We use the size we store rather than the length of the array
return this.size;
}
void add(int value) {
// if we won't have enough room in the array, make a new one.
if (size >= this.data.length - 1) {
// Overallocate by 2x
int newLength = this.data.length * 2;
if (newLength == 0) {
newLength = 2; // Unfortunately 0 * 2 is 0, so account for that
}
int[] newArray = new int[newLength];
for (int i = 0; i < this.data.length; i++) {
newArray[i] = this.data[i];
}
this.data = newArray;
}
// And at this point we know the array is big enough
this.data[size] = value;
this.size++;
}
}
1
I love obvious and circular statements like this, if you haven't noticed.