Section12.18Step 4.3: Building Skeletons (Other Methods)
We continue with Design Recipe Step 4, outlining the logical skeletons for the remaining methods required by the ListADT<T> interface: those for accessing elements, querying the list’s state, and searching. We consult the contract, identify checks, and plan the core logic steps using comments.
/**
* Returns the element at the specified position. ...
* @param index position (0 to size-1 inclusive)
* @return the element
* @throws IndexOutOfBoundsException if index is invalid
*/
@Override
public T get(int index) {
// --- Skeleton Plan ---
// 1. Check index bounds (0 <= index < size); throw IndexOutOfBoundsException if invalid.
// 2. Return buffer[index];
}
/**
* Replaces the element at the specified position. ...
* @param index position (0 to size-1 inclusive)
* @param item element to store (cannot be null)
* @return the element previously at the position
* @throws IndexOutOfBoundsException if index is invalid
* @throws IllegalArgumentException if item is null
*/
@Override
public T set(int index, T item) {
// --- Skeleton Plan ---
// 1. Check for null item; throw IllegalArgumentException if invalid.
// 2. Check index bounds (0 <= index < size); throw IndexOutOfBoundsException if invalid.
// 3. Store current buffer[index] in a temporary variable ('oldItem').
// 4. Update the array: buffer[index] = item;
// 5. Return 'oldItem'.
}
/**
* Returns the first element ...
* @return the first element
* @throws java.util.NoSuchElementException if list is empty
*/
@Override
public T first() {
// --- Skeleton Plan ---
// 1. Check if empty (size == 0); throw NoSuchElementException if true.
// 2. Return buffer[0].
}
/**
* Returns the last element ...
* @return the last element
* @throws java.util.NoSuchElementException if list is empty
*/
@Override
public T last() {
// --- Skeleton Plan ---
// 1. Check if empty (size == 0); throw NoSuchElementException if true.
// 2. Return buffer[size - 1].
}
/**
* Returns the position of the first occurrence ... or -1 if not found.
* @param item element to search for
* @return the index, or -1
*/
@Override
public int indexOf(T item) {
// --- Skeleton Plan ---
// 1. Plan: Iterate with index 'i' from 0 to size - 1.
// 2. Inside loop, compare 'item' with buffer[i] using null-safe equals.
// (e.g., check if both are null, or if item is not null and item.equals(buffer[i])).
// 3. If a match is found, return index 'i' immediately.
// 4. If loop finishes without a match, return -1.
}
Identifying Reuse: We could iterate through the list similar to indexOf. However, notice that an item "is contained" in the list if and only if its index is *not* -1. We can leverage the logic we just planned for indexOf.
// Javadoc implies standard contains behavior
@Override
public boolean contains(T item) {
// --- Skeleton Plan (Leveraging indexOf logic) ---
// 1. Perform the logic planned for indexOf(item). Let the result be 'foundIndex'.
// 2. Return true if 'foundIndex' is not -1, otherwise return false.
// - Return (foundIndex >= 0);
}
This plan reuses the search logic, making the plan for contains simpler and inherently consistent with indexOf. During implementation (Step 5), this translates to calling the actual indexOf method.
With the planning for all method skeletons now complete, the corresponding code state (containing all method skeletons) can be found on the dr-step-4.3-other-skeletons branch in the repository.
With these skeletons, we now have a logical plan outlined for all methods required by the ListADT<T> interface. We’ve considered the necessary checks based on the contract, planned the core logic steps, identified potential internal helper logic (resizing, shifting), and even planned for reuse between methods like contains and indexOf.
This completes Design Recipe Step 4. The next crucial phase is Design Recipe Step 5: Implementation, Testing & Refinement, where we will translate these skeletons into working Java code, using the unit tests (discussed in Section 11) to verify our progress along the way.