Joseph Haugh
University of New Mexico
int[] scores = new int[30]; // guess: at most 30 students?
int count = 0;
int[] scores = new int[30];
int count = 0;
scores[count] = 92; count++;
scores[count] = 87; count++;
scores[count] = 74; count++;
// ... keep going ...
scores[count] = 81; count++; // 31st student: ArrayIndexOutOfBoundsException!
count yourselfArrayList for exactly this, but today we’ll build one ourselves to understand how it worksIntList class that acts like a resizable list of int valuespublic class IntList {
private static final int INITIAL_CAPACITY = 10;
private int[] xs;
private int nextIndex;
public IntList() {
xs = new int[INITIAL_CAPACITY];
nextIndex = 0;
}
}
xs is the backing array: the actual storagenextIndex tracks how many elements have been addedpublic class IntList {
// fields, constructor ...
public int size() {
return nextIndex;
}
public boolean isEmpty() {
return size() == 0;
}
}
nextIndex always equals the number of elements, so size() just returns itisEmpty() reuses size() rather than checking nextIndex directlypublic class IntList {
// fields and constructor ...
public void add(int x) {
growIfFull();
xs[nextIndex] = x;
nextIndex++;
}
}
growIfFull() to ensure there is roomx at position nextIndex and advances the counterpublic class IntList {
// fields, constructor, add ...
private void growIfFull() {
if (nextIndex >= xs.length) {
int[] newXs = new int[xs.length * 2];
for (int i = 0; i < xs.length; i++) {
newXs[i] = xs[i];
}
xs = newXs;
}
}
}
nextIndex >= xs.length), allocate a new array twice as largexs at the new array; the old one is discardedadd() low; most calls do no copying at allpublic class IntList {
// fields, constructor, add, growIfFull ...
public int get(int i) {
if (i < 0 || i >= size()) {
throw new IndexOutOfBoundsException(
"Index " + i + " out of bounds for size " + size());
}
return xs[i];
}
}
i is a valid index before accessing the arrayxs[i] directlypublic class IntList {
// fields, constructor, add, growIfFull, get ...
public int pop() {
if (nextIndex <= 0) {
throw new IllegalStateException("List is empty");
}
int result = xs[nextIndex - 1];
nextIndex--;
return result;
}
}
nextIndex is all it takes; the value in xs is simply ignored from now onvoid main() {
IntList scores = new IntList();
scores.add(92);
scores.add(87);
scores.add(74);
IO.println(scores.size()); // 3
IO.println(scores.get(0)); // 92
IO.println(scores.get(2)); // 74
int last = scores.pop();
IO.println(last); // 74
IO.println(scores.size()); // 2
}
count variable yourselfIntList only stores int valuesString values you’d have to write a separate StringListDoubleList for doubles, and so onList<Integer>, List<String>, List<Double>ArrayList uses under the hoodget(-1) is not a logic error you can prevent in the compiler; it depends on what value i has when the program runsthrow new ExceptionType("message")if (i < 0 || i >= size()) {
throw new IndexOutOfBoundsException(
"Index " + i + " out of bounds for size " + size());
}
throw stops execution immediately and sends the exception up to the callerIndexOutOfBoundsException: bad indexIllegalStateException: operation not valid in current stateIllegalArgumentException: caller passed an invalid argumentArrays vs Lists
| Array | IntList | |
|---|---|---|
| Size | Fixed at creation | Grows automatically |
| Access by index | Yes | Yes |
| Track count | Manual | Built-in (size()) |
| Add beyond capacity | Crash | Handled |
IntList Operations
add(x): append to endget(i): read element at indexpop(): remove and return lastsize(): number of elementsisEmpty(): true if no elementsindexOf(x): returns the index of the first occurrence of x