Build a Generic ArrayList Gradebook
Build a tested Java gradebook with ArrayList and reusable generic methods.
Introduction
30 Second Summary
Exam questions often hide their hardest detail in one tiny choice. A program you can rerun turns that uncertainty into something you can see.
In this project, you will build a one-file Java gradebook that makes ArrayList behavior visible in the console. A PASS/FAIL test harness checks results produced by generic methods across names and scores.
What You'll Build
Your final demo prints a changing gradebook before finishing with a clean summary of eleven passing checks.
By the end of this project, you'll have:
- A visible gradebook that prints student names and scores in insertion order.
- A removal comparison that makes method overloading visible by contrasting index removal with value removal.
- A self-checking practice suite that runs generic helpers before reporting eleven passing checks.
- Secret Mission: Reverse any typed ArrayList in place by reusing the generic swap method.
Are there any prerequisites?
You need basic Java experience plus IntelliJ IDEA on Windows. The first step helps you select or download JDK 25.
Before We Start
This first checkpoint locks in what your exam lab demonstrates before the hands-on work begins. You will connect typed Java ArrayList operations with generic methods and plain main-based tests while focusing on why integer removal can produce a surprising result.
Set Up the IntelliJ Project
An exam lab only helps when the environment compiles the same code every time. A known Java version removes uncertainty before you study collection behavior.
In this step, you will use IntelliJ IDEA with the JDK version 25. You will create one regular Java class that proves the project can compile and run.
In this step, get ready to:
- Create an IntelliJ Java project that uses JDK 25.
- Create src/ArrayListExamLab.java as a regular Java class.
- Run the class from the gutter and confirm the readiness output.
Create the Java project
The JDK supplies the tools that compile and run Java. Selecting version 25 keeps your project aligned with the code used throughout this lab.
- Press the Windows key to open Windows search.
- Type IntelliJ IDEA into the search field.
- Press Enter to open IntelliJ IDEA.
- Click New Project on the Welcome screen.
- Select Java from the project list.
- Select IntelliJ for the Build system.
- Open the JDK list to check which version is available.
✔️ I see JDK 25
- Select JDK 25 from the list.
The project wizard now targets the required Java version.
ⓧ I only see an older JDK
The older JDK does not match this lab's environment. IntelliJ IDEA can download the required version from the project wizard.
- Choose Download JDK from the JDK list.
- Select version 25.
- Wait for the JDK download to complete.
- Confirm the JDK field shows 25.
ⓧ No JDK is listed
The project wizard needs a configured JDK before it can create a Java project. You can download the required version without leaving IntelliJ IDEA.
- Choose Download JDK from the JDK list.
- Select version 25.
- Wait for the JDK download to complete.
- Confirm the JDK field shows 25.
- Enter ArrayListExamLab in the Name field.
- Leave Add sample code disabled.
- Click Create.
The ArrayListExamLab project opens with a src folder in the Project tool window. That folder confirms your Java source area is ready.
Project Did Not Open?
- Confirm the JDK field shows 25 before you click Create.
- Wait for any active JDK download to finish before creating the project.
Still stuck? Help me troubleshoot my IntelliJ Java project setup.
Create the regular Java class
A regular Java class places the entry point inside a named class. This matches the structure you will use for the gradebook and its plain main-based tests.
- Select the src folder in the Project tool window.
- Right-click the src folder.
- Point to New.
- Click Java Class.
- Type ArrayListExamLab in the New Java Class popup.
- Press Enter to create the class.
- Replace the generated contents of src/ArrayListExamLab.java by pasting this code:
public class ArrayListExamLab {
public static void main(String[] args) {
System.out.println("READY");
}
}
What Does This Code Do?
- The ArrayListExamLab class gives the file its executable Java structure.
- The public static void main(String[] args) method is the application's entry point.
- The System.out.println("READY") statement prints a visible readiness message to standard output.
- Press Ctrl+S to save src/ArrayListExamLab.java.
- Confirm the Project tool window lists ArrayListExamLab.java under src.
Class File in the Wrong Place?
- Confirm you selected the src folder before creating the Java class.
- Check that the file name is exactly ArrayListExamLab.java.
- Check that the public class name is exactly ArrayListExamLab.
Need help? Help me fix the location or name of my Java class.
✔️ Awesome, I've got everything!
Your saved class now contains the entry point and the readiness message.
ⓧ I'd like to double check the full code
public class ArrayListExamLab {
public static void main(String[] args) {
System.out.println("READY");
}
}
What Should the Complete File Contain?
The complete file contains one public class. Its main method prints the readiness message.
Run the readiness check
Running the entry point proves that IntelliJ IDEA can compile the class with your selected JDK. Before you run it, what output do you expect the main method to produce?
- Find the gutter Run icon next to main.
- Click the gutter Run icon.
- Select Run 'ArrayListExamLab.main()'.
You will see READY in the Run tool window. The process finishes with exit code 0.
Your Java environment is ready. IntelliJ IDEA can now compile and run the class that becomes your gradebook.
Run Icon Missing or Output Different?
- Confirm ArrayListExamLab.java is inside the src folder.
- Confirm the class contains public static void main(String[] args).
- Confirm the print statement contains READY in uppercase letters.
Still blocked? Help me diagnose why my Java class will not run from the gutter.
Your project has a working entry point and a confirmed JDK. Next, you will turn this readiness check into the first visible gradebook.
Build the Visible Gradebook
Your class already runs in IntelliJ IDEA with JDK 25. That working entry point gives you a stable place to build the gradebook.
A visible list of names gives you a concrete result before subtler collection behavior. Matching scores make the gradebook useful.
In this step, you will create two typed ArrayList collections. Indexed loops will print their contents in insertion order.
In this step, get ready to:
- Create a typed student list.
- Create a typed score list.
- Print each list with an indexed loop.
Build the typed gradebook
Each list accepts only its declared element type. Matching positions pair Ava with 84, Ben with 91, and Chloe with 76.
- Switch back to src/ArrayListExamLab.java in the editor from the previous step.
- Press Cmd+A (macOS) or Ctrl+A (Windows) to select the starter class.
- Replace the selected starter class by pasting the complete gradebook below:
import java.util.ArrayList;
public class ArrayListExamLab {
public static void main(String[] args) {
ArrayList<String> students = new ArrayList<>();
students.add("Ava");
students.add("Ben");
students.add("Chloe");
ArrayList<Integer> scores = new ArrayList<>();
scores.add(84);
scores.add(91);
scores.add(76);
System.out.println("Initial students:");
for (int i = 0; i < students.size(); i++) {
System.out.println(i + ": " + students.get(i));
}
System.out.println("Initial scores:");
for (int i = 0; i < scores.size(); i++) {
System.out.println(i + ": " + scores.get(i));
}
}
}
What does this code do?
- The import makes Java's ArrayList class available inside your file.
- The students collection accepts String values such as Ava.
- The scores collection uses the Integer wrapper class for whole-number scores.
- The diamond operator <> uses type inference to copy the declared element type into the constructor.
- Each add call appends one value to the end of its collection.
- Each loop reads values with get(i) while i remains below size().
- Save src/ArrayListExamLab.java by pressing Cmd+S (macOS) or Ctrl+S (Windows).
✔️ Awesome, I've got everything!
Good progress. Your saved class now contains the two typed collections plus the loops that make them visible.
ⓧ I'd like to double check the full code
- Compare your saved src/ArrayListExamLab.java file with this reference:
import java.util.ArrayList;
public class ArrayListExamLab {
public static void main(String[] args) {
ArrayList<String> students = new ArrayList<>();
students.add("Ava");
students.add("Ben");
students.add("Chloe");
ArrayList<Integer> scores = new ArrayList<>();
scores.add(84);
scores.add(91);
scores.add(76);
System.out.println("Initial students:");
for (int i = 0; i < students.size(); i++) {
System.out.println(i + ": " + students.get(i));
}
System.out.println("Initial scores:");
for (int i = 0; i < scores.size(); i++) {
System.out.println(i + ": " + scores.get(i));
}
}
}
What are you checking?
This reference shows the exact target state for this step. Your import belongs above the class declaration.
The student loop belongs before the score heading. Both loops remain inside main.
Predict the second student's index
Before you run the gradebook, which index do you expect beside Ben?
- Click the gutter Run icon next to main.
What should I see?
Under Initial students:, you will see 0: Ava. The next line is 1: Ben.
The final student line is 2: Chloe. Ben's 1 confirms zero-based indexing.
Under Initial scores:, you will see 0: 84. The next line is 1: 91.
The final score line is 2: 76. The Run tool window finishes with exit code 0.
You now have your first visible gradebook. Both typed collections print in the same order that you added their values.
Still seeing READY?
- Confirm the ArrayList import sits above the class declaration.
- Save src/ArrayListExamLab.java before using the gutter Run icon.
- Check that both loops remain inside main if the compiler points to a brace problem.
If the output still looks different, help me compare my gradebook code with the expected structure.
Your names and scores are now visible in matching positions. Next, you will put this gradebook through its first collection changes.
Trigger the Remove Overload Trap
Your typed ArrayList gradebook already prints three students and three scores in insertion order. That visible baseline makes each change easy to trace.
A gradebook also needs to locate existing entries. It needs to change stored scores.
Method overloading lets one method name support different parameter types. Integer arguments make removal behavior easy to misread.
You will run the ambiguous call first. The console output will reveal what Java chose.
In this step, get ready to:
- Locate Ben through collection searches.
- Update the last score in place.
- Expose the integer removal trap through console output.
Search for Ben and update a score
Search methods let the program answer questions about the current list. Indexed updates change one stored value while preserving the surrounding order.
- In src/ArrayListExamLab.java, delete the empty line immediately before System.out.println("Initial scores:");.
- Add the search and update operations after the loop that prints the initial scores by pasting this code:
System.out.println("Ben present: " + students.contains("Ben"));
System.out.println("Ben index: " + students.indexOf("Ben"));
scores.set(2, 88);
System.out.println("Updated last score: " + scores.get(2));
What does this code do?
- The contains("Ben") call checks whether the student list includes Ben.
- The indexOf("Ben") call returns Ben's first matching index.
- The set(2, 88) call replaces the score at index 2.
- The get(2) call reads the updated score for printing.
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
You should see Ben present: true, Ben index: 1, and Updated last score: 88 in the Run tool window.
Good. Your gradebook can now locate Ben. The last score is now 88.
Seeing the wrong search result?
- Check that the student entries remain Ava, Ben, and Chloe in that order.
- Check that the new lines sit after both initial printing loops.
Still stuck? Help me debug my ArrayList search and score update output.
Remove the second student by index
Zero-based indexing gives the second student an index of 1. Removing that position shifts every later student one place to the left.
- Add the index-removal demonstration after the updated-score output by pasting this code:
students.remove(1);
System.out.println("Students after removing index 1:");
for (int i = 0; i < students.size(); i++) {
System.out.println(i + ": " + students.get(i));
}
What does this code do?
- The remove(1) call uses the remove(int index) overload to remove the student at index 1.
- The indexed loop prints the shorter list so you can observe the shifted position.
- Save src/ArrayListExamLab.java.
Before you run it, predict which student occupies index 1 after Ben is removed.
- Click the gutter Run icon next to main.
Under Students after removing index 1:, you should see Ava at index 0 and Chloe at index 1.
Still seeing Ben?
- Check that students.remove(1); appears before the new printing loop.
- Check that the new loop uses students.size() as its boundary.
Need another pair of eyes? Help me debug why Ben remains in my students list.
Run the integer removal trap
A separate integer list isolates the overloaded call from the gradebook data. Its printed survivors show exactly which element Java removes.
- Add the isolated integer example after the student-removal loop by pasting this code:
ArrayList<Integer> indexRemoval = new ArrayList<>();
indexRemoval.add(1);
indexRemoval.add(10);
indexRemoval.add(20);
indexRemoval.remove(1);
System.out.println("After remove(1):");
for (int i = 0; i < indexRemoval.size(); i++) {
System.out.println(indexRemoval.get(i));
}
What is this test isolating?
- The indexRemoval list starts with the integer values 1, 10, and 20.
- The remove(1) call is the only operation that changes the list.
- The final loop prints each surviving value so the result can settle the prediction.
- Save src/ArrayListExamLab.java.
Before you run this, predict whether remove(1) removes the value 1 or the element stored at index 1.
- Click the gutter Run icon next to main.
Under After remove(1):, you should see 1 followed by 20.
The overload trap worked
The argument 1 is an integer. Java therefore selects remove(int index).
Index 1 held the value 10. The list keeps the value 1 because that value was stored at index 0.
Seeing different remaining values?
- Check that indexRemoval receives 1, 10, and 20 in that order.
- Check that the removal line is exactly indexRemoval.remove(1);.
- Check that the final loop prints values from indexRemoval.
Still seeing another result? Help me debug my integer ArrayList removal demonstration.
✔️ Awesome, I've got everything!
Your file now matches this step's finished version.
ⓧ I'd like to double check the full code
import java.util.ArrayList;
public class ArrayListExamLab {
public static void main(String[] args) {
ArrayList<String> students = new ArrayList<>();
students.add("Ava");
students.add("Ben");
students.add("Chloe");
ArrayList<Integer> scores = new ArrayList<>();
scores.add(84);
scores.add(91);
scores.add(76);
System.out.println("Initial students:");
for (int i = 0; i < students.size(); i++) {
System.out.println(i + ": " + students.get(i));
}
System.out.println("Initial scores:");
for (int i = 0; i < scores.size(); i++) {
System.out.println(i + ": " + scores.get(i));
}
System.out.println("Ben present: " + students.contains("Ben"));
System.out.println("Ben index: " + students.indexOf("Ben"));
scores.set(2, 88);
System.out.println("Updated last score: " + scores.get(2));
students.remove(1);
System.out.println("Students after removing index 1:");
for (int i = 0; i < students.size(); i++) {
System.out.println(i + ": " + students.get(i));
}
ArrayList<Integer> indexRemoval = new ArrayList<>();
indexRemoval.add(1);
indexRemoval.add(10);
indexRemoval.add(20);
indexRemoval.remove(1);
System.out.println("After remove(1):");
for (int i = 0; i < indexRemoval.size(); i++) {
System.out.println(indexRemoval.get(i));
}
}
}
You have now seen an integer argument select index removal. Next, you'll make value removal explicit through PASS/FAIL checks.
Fix Removal and Add Tests
In the last step, your integer ArrayList used remove(1) as an index-removal call. The value 1 stayed in the list while 10 was removed.
This step makes value removal explicit with Integer.valueOf(1). You will also turn each core operation into a plain Java PASS/FAIL check inside main.
In this step, get ready to:
- Build a reusable PASS/FAIL test harness with result counters.
- Remove an integer value through the object-removal overload.
- Test each core collection operation with an executable condition.
Build the PASS/FAIL harness
A test harness turns an expected result into a condition that the program can evaluate. The counters record how many conditions pass or fail during one run.
- In src/ArrayListExamLab.java from earlier, add the counters directly below the opening brace of ArrayListExamLab by copying this code:
private static int passed = 0;
private static int failed = 0;
What do these counters track?
- The passed field counts conditions that evaluate to true.
- The failed field counts conditions that evaluate to false.
- Scroll to the closing brace of main near the bottom of the file.
- Add the check helper between the closing brace of main and the final class brace by copying this code:
private static void check(String testName, boolean condition) {
if (condition) {
passed++;
System.out.println("PASS: " + testName);
} else {
failed++;
System.out.println("FAIL: " + testName);
}
}
How does the helper work?
- The condition parameter receives the result of a test expression.
- A true condition increments passed before printing a line that begins with PASS:.
- A false condition increments failed before printing a line that begins with FAIL:.
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
The Run tool window finishes with exit code 0. That successful run proves your new harness structure compiles.
Seeing a compilation error?
Check that both counters sit inside the ArrayListExamLab class. They must stay outside main.
Check that the check method sits after main while remaining inside the class.
Still stuck? Help me place the counters and check method correctly.
Remove an integer value explicitly
The method overloading in remove lets the same method name accept an index or an object. Integer.valueOf(1) creates an integer wrapper object that selects object removal.
- In src/ArrayListExamLab.java, find indexRemoval.remove(1);.
- Replace the output heading and loop directly below that line with these checks:
check("remove(1) keeps the value 1", indexRemoval.contains(1));
check("remove(1) removes the value at index 1", !indexRemoval.contains(10));
What do these checks prove?
- The first condition confirms that remove(1) keeps the element whose value is 1.
- The second condition confirms that the element at index 1 was 10.
- Add a fresh value-removal example directly below the two indexRemoval checks by copying this code:
ArrayList<Integer> valueRemoval = new ArrayList<>();
valueRemoval.add(1);
valueRemoval.add(10);
valueRemoval.add(20);
valueRemoval.remove(Integer.valueOf(1));
check("remove(Integer.valueOf(1)) removes value 1",
!valueRemoval.contains(1));
check("value removal keeps value 10", valueRemoval.contains(10));
Why does value removal work?
- The new list begins with the same values as the index-removal example.
- The wrapper returned by Integer.valueOf(1) selects object removal.
- The checks confirm that the value 1 is removed while the value 10 remains.
Before you run the program, which removal example do you expect to keep the value 1?
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
You will see four removal checks beginning with PASS:. You have now proved both overload behaviors with executable evidence.
Seeing a failed removal check?
Confirm that indexRemoval uses remove(1).
Confirm that valueRemoval uses remove(Integer.valueOf(1)).
Need another pair of eyes? Help me diagnose my integer removal checks.
Turn behavior into executable checks
The remaining direct output shows values without judging whether they are correct. Boolean checks make each expectation repeatable whenever you run the lab.
- Delete the initial student-printing and score-printing sections above the search operations.
- Replace the direct search and score-update output with these checks:
check("three students were added", students.size() == 3);
check("Ben is present", students.contains("Ben"));
check("Ben is at index 1", students.indexOf("Ben") == 1);
scores.set(2, 88);
check("the last score was updated", scores.get(2).intValue() == 88);
What do the core checks cover?
- The first three conditions test size, contains, and indexOf.
- The final condition tests set through a follow-up get call.
- The intValue() call reads the updated wrapper value as a primitive integer.
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
You will see eight lines beginning with PASS: across the search, update, and removal behaviors.
Seeing one of the first checks fail?
Confirm that the students remain in the original order before students.remove(1) runs.
Confirm that scores.set(2, 88) appears before the updated-score check.
Need help tracing the condition? Help me inspect the failing core ArrayList check.
- Find students.remove(1);.
- Replace the student output heading and loop directly below it with this check:
check("removing index 1 removes Ben",
students.size() == 2 && !students.contains("Ben"));
Why test two conditions together?
The condition proves that the list shrank to two students. It also proves that Ben is no longer present.
- Add the final reporting block after the two valueRemoval checks by copying this code:
System.out.println("Final students:");
for (int i = 0; i < students.size(); i++) {
System.out.println(i + ": " + students.get(i));
}
System.out.println("Final scores:");
for (int i = 0; i < scores.size(); i++) {
System.out.println(i + ": " + scores.get(i));
}
System.out.println("Passed: " + passed);
System.out.println("Failed: " + failed);
What does the final report show?
- The indexed loops print the final student and score lists in their current order.
- The last two lines expose the totals recorded by the test harness.
- Save src/ArrayListExamLab.java.
Before the final run, do you expect every check to pass after both removal overloads have been tested separately?
- Click the gutter Run icon next to main.
You will see nine core-operation lines beginning with PASS:.
The summary prints Passed: 9 followed by Failed: 0. Your gradebook now checks its own behavior every time it runs.
Seeing a failure in the final run?
Read the text after FAIL: to identify the operation whose condition returned false.
Check that each operation runs before the condition that tests its result.
Want help with a specific result? Help me trace my failing PASS/FAIL check.
✔️ Awesome, I've got everything!
Great work. Save src/ArrayListExamLab.java with all nine checks passing.
ⓧ I'd like to double check the full code
import java.util.ArrayList;
public class ArrayListExamLab {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
ArrayList<String> students = new ArrayList<>();
students.add("Ava");
students.add("Ben");
students.add("Chloe");
ArrayList<Integer> scores = new ArrayList<>();
scores.add(84);
scores.add(91);
scores.add(76);
check("three students were added", students.size() == 3);
check("Ben is present", students.contains("Ben"));
check("Ben is at index 1", students.indexOf("Ben") == 1);
scores.set(2, 88);
check("the last score was updated", scores.get(2).intValue() == 88);
students.remove(1);
check("removing index 1 removes Ben",
students.size() == 2 && !students.contains("Ben"));
ArrayList<Integer> indexRemoval = new ArrayList<>();
indexRemoval.add(1);
indexRemoval.add(10);
indexRemoval.add(20);
indexRemoval.remove(1);
check("remove(1) keeps the value 1", indexRemoval.contains(1));
check("remove(1) removes the value at index 1", !indexRemoval.contains(10));
ArrayList<Integer> valueRemoval = new ArrayList<>();
valueRemoval.add(1);
valueRemoval.add(10);
valueRemoval.add(20);
valueRemoval.remove(Integer.valueOf(1));
check("remove(Integer.valueOf(1)) removes value 1",
!valueRemoval.contains(1));
check("value removal keeps value 10", valueRemoval.contains(10));
System.out.println("Final students:");
for (int i = 0; i < students.size(); i++) {
System.out.println(i + ": " + students.get(i));
}
System.out.println("Final scores:");
for (int i = 0; i < scores.size(); i++) {
System.out.println(i + ": " + scores.get(i));
}
System.out.println("Passed: " + passed);
System.out.println("Failed: " + failed);
}
private static void check(String testName, boolean condition) {
if (condition) {
passed++;
System.out.println("PASS: " + testName);
} else {
failed++;
System.out.println("FAIL: " + testName);
}
}
}
How to compare your file
Compare the placement of the counters, each check, the final reporting loops, and the check helper. Your file should match this reference exactly.
Your core collection operations now come with repeatable evidence. Next, you will replace repeated logic with reusable generic methods.
Extract Generic Methods
Your core ArrayList checks now run cleanly in IntelliJ IDEA. The PASS/FAIL harness proves index removal behaves differently from value removal.
The file still repeats list logic for each element type. Generic methods solve that limitation with reusable operations that remain type-safe.
In this step, get ready to:
- Replace repeated printing loops with one generic method.
- Swap student elements with one reusable generic method.
- Find the largest score through a bounded type parameter.
Extract the generic printer
A generic method declares a type parameter for the values it processes. The compiler infers that type when you pass either the student list or the score list.
- In src/ArrayListExamLab.java, locate the closing brace of check.
- Add the reusable printer below check by copying this method:
private static <T> void printList(ArrayList<T> items) {
for (int i = 0; i < items.size(); i++) {
System.out.println(i + ": " + items.get(i));
}
}
What does this method do?
- The <T> declaration introduces the method's element type before the return type.
- The ArrayList<T> parameter accepts an ArrayList whose elements share that inferred type.
- The indexed loop prints every element without assuming that each value is a String or an Integer.
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
The existing checks still compile. The summary remains Passed: 9 followed by Failed: 0.
Seeing a compiler error?
Check that printList sits inside the ArrayListExamLab class. It must sit outside the check method.
Still stuck? Help me place my generic printList method correctly.
- In main, select the code from public static void main(String[] args) { through scores.add(76);.
- Replace the selection with this updated opening:
public static void main(String[] args) {
System.out.println("ARRAYLIST EXAM LAB");
ArrayList<String> students = new ArrayList<>();
students.add("Ava");
students.add("Ben");
students.add("Chloe");
ArrayList<Integer> scores = new ArrayList<>();
scores.add(84);
scores.add(91);
scores.add(76);
System.out.println("Initial students:");
printList(students);
System.out.println("Initial scores:");
printList(scores);
Why call the method twice?
The first call infers T as String from students. The second call infers T as Integer from scores.
The heading gives the console lab a clear starting point. The two method calls expose each list before later operations change its contents.
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
The Run tool window starts with ARRAYLIST EXAM LAB. You will see three initial students followed by three initial scores.
Initial lists missing?
Check that both printList calls appear after the lists receive their three values. A call placed before the add statements prints an empty list.
Need help? Help me find why my initial lists do not print.
- In main, select the final output block from System.out.println("Final students:"); through System.out.println("Failed: " + failed);.
- Replace the selection with this generic printing block:
System.out.println("Final students:");
printList(students);
System.out.println("Final scores:");
printList(scores);
System.out.println("Passed: " + passed);
System.out.println("Failed: " + failed);
What changed?
Both repeated loops now delegate to printList. The method keeps the zero-based indexes visible for any accepted element type.
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
That refactor is working: the initial lists still contain three indexed values. The final lists also retain their indexed output.
Final output disappeared?
Confirm that the final calls use the existing variables students and scores. Check that both calls remain inside main.
Still missing output? Help me troubleshoot my final printList calls.
Swap typed elements safely
A generic swap keeps the list's element type consistent while two positions exchange values. The local variable firstItem preserves the first element before set replaces it.
- Place the swap method below printList by copying this code:
private static <T> void swap(
ArrayList<T> items, int firstIndex, int secondIndex) {
T firstItem = items.get(firstIndex);
items.set(firstIndex, items.get(secondIndex));
items.set(secondIndex, firstItem);
}
How does the swap work?
- The method receives one typed list plus two indexes.
- The firstItem variable holds the original value from firstIndex.
- The two set calls exchange the elements without changing their type.
- In main, locate the check named value removal keeps value 10.
- Add the generic swap check below that existing check by copying this code:
swap(students, 0, 1);
check("generic swap changes the first student",
students.get(0).equals("Chloe"));
What does this check prove?
Removing Ben leaves Ava at index 0 and Chloe at index 1. The swap moves Chloe into the first position.
The compiler infers String as the method type from students. No explicit type argument is needed at the call site.
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
Your tenth passing check proves the generic swap changed the first student to Chloe. The summary now shows Passed: 10 followed by Failed: 0.
Swap check failing?
Check that students.remove(1) still runs before swap(students, 0, 1). The expected first value depends on Ben already being removed.
Need another pair of eyes? Help me debug my generic swap check.
Find the largest comparable value
The Comparable contract gives the final helper a type-safe ordering rule. Its compareTo result tells the method when a new value is greater than the current largest value.
- Place the findLargest method below swap by copying this code:
private static <T extends Comparable<T>> T findLargest(
ArrayList<T> items) {
T largest = items.get(0);
for (int i = 1; i < items.size(); i++) {
if (items.get(i).compareTo(largest) > 0) {
largest = items.get(i);
}
}
return largest;
}
Why does this method need a bound?
- The bound T extends Comparable<T> requires each accepted element type to support comparisons with its own type.
- The largest variable begins with the first list element because this project calls the method with a non-empty score list.
- A positive compareTo result replaces the current largest value.
- The return type remains T so the result preserves the list's element type.
- In main, locate the check named generic swap changes the first student.
- Add the largest-score check below the existing swap check by copying this code:
check("largest score is 91",
findLargest(scores).intValue() == 91);
What does the final check prove?
The method compares the scores after the last value changes from 76 to 88. The largest value remains 91.
The call also proves that the compiler infers Integer for the bounded generic method.
Before you run the completed lab, do you expect every check to pass after both element types use the generic methods?
- Save src/ArrayListExamLab.java.
- Click the gutter Run icon next to main.
Every core-operation line begins with PASS. The final summary shows Passed: 11 followed by Failed: 0.
Strong finish. Your gradebook now proves that one generic implementation can print typed lists or swap their elements or find their largest comparable value.
Summary not showing eleven passes?
Check that the findLargest(scores) call appears after the score at index 2 changes to 88.
Compare each generic method name with its call inside main. A spelling mismatch prevents the completed test suite from compiling.
Still seeing a failure? Help me trace my eleven gradebook checks.
✔️ Awesome, I've got everything!
Your completed core lab now matches the target structure. All eleven checks pass with zero failures.
ⓧ I'd like to double check the full code
import java.util.ArrayList;
public class ArrayListExamLab {
private static int passed = 0;
private static int failed = 0;
public static void main(String[] args) {
System.out.println("ARRAYLIST EXAM LAB");
ArrayList<String> students = new ArrayList<>();
students.add("Ava");
students.add("Ben");
students.add("Chloe");
ArrayList<Integer> scores = new ArrayList<>();
scores.add(84);
scores.add(91);
scores.add(76);
System.out.println("Initial students:");
printList(students);
System.out.println("Initial scores:");
printList(scores);
check("three students were added", students.size() == 3);
check("Ben is present", students.contains("Ben"));
check("Ben is at index 1", students.indexOf("Ben") == 1);
scores.set(2, 88);
check("the last score was updated", scores.get(2).intValue() == 88);
students.remove(1);
check("removing index 1 removes Ben",
students.size() == 2 && !students.contains("Ben"));
ArrayList<Integer> indexRemoval = new ArrayList<>();
indexRemoval.add(1);
indexRemoval.add(10);
indexRemoval.add(20);
indexRemoval.remove(1);
check("remove(1) keeps the value 1", indexRemoval.contains(1));
check("remove(1) removes the value at index 1", !indexRemoval.contains(10));
ArrayList<Integer> valueRemoval = new ArrayList<>();
valueRemoval.add(1);
valueRemoval.add(10);
valueRemoval.add(20);
valueRemoval.remove(Integer.valueOf(1));
check("remove(Integer.valueOf(1)) removes value 1",
!valueRemoval.contains(1));
check("value removal keeps value 10", valueRemoval.contains(10));
swap(students, 0, 1);
check("generic swap changes the first student",
students.get(0).equals("Chloe"));
check("largest score is 91",
findLargest(scores).intValue() == 91);
System.out.println("Final students:");
printList(students);
System.out.println("Final scores:");
printList(scores);
System.out.println("Passed: " + passed);
System.out.println("Failed: " + failed);
}
private static void check(String testName, boolean condition) {
if (condition) {
passed++;
System.out.println("PASS: " + testName);
} else {
failed++;
System.out.println("FAIL: " + testName);
}
}
private static <T> void printList(ArrayList<T> items) {
for (int i = 0; i < items.size(); i++) {
System.out.println(i + ": " + items.get(i));
}
}
private static <T> void swap(
ArrayList<T> items, int firstIndex, int secondIndex) {
T firstItem = items.get(firstIndex);
items.set(firstIndex, items.get(secondIndex));
items.set(secondIndex, firstItem);
}
private static <T extends Comparable<T>> T findLargest(
ArrayList<T> items) {
T largest = items.get(0);
for (int i = 1; i < items.size(); i++) {
if (items.get(i).compareTo(largest) > 0) {
largest = items.get(i);
}
}
return largest;
}
}
How to compare your file
Check the order of the three generic methods below check. Confirm that main calls each method with the matching list.
Secret mission
Reverse Any Typed ArrayList
Extend your gradebook with a generic in-place reversal algorithm. You will reuse the existing swap method to reverse a typed list of review topics and prove the result with a twelfth passing check.
Clean Up Your Resources
Clean Up Your Resources
This lab runs entirely on your Windows computer with no ongoing costs. Choose to keep the IntelliJ IDEA project ready, close it for later, or delete its local files.
Resources you used:
- The local ArrayListExamLab project folder containing src/ArrayListExamLab.java.
Keep everything running
No action is needed. Choose this option if you want the exam lab ready for more practice.
- Leave the ArrayListExamLab project in its current location.
- Run src/ArrayListExamLab.java from the gutter whenever you want to review the twelve checks.
- Keep the project configured for JDK 25 so the existing setup remains ready.
Pause - I'll come back to this later
Pausing means closing the editor. Your project files remain available for your next study session.
- Save src/ArrayListExamLab.java.
- Close IntelliJ IDEA.
- Reopen the existing ArrayListExamLab project when you return.
Delete - I don't want to use this again
Deletion permanently removes the lab from this computer. Save a copy elsewhere first if you want to keep the code for exam revision.
- Copy src/ArrayListExamLab.java to another folder if you want to keep the finished program.
- Close IntelliJ IDEA.
- Open the Windows file browser from the taskbar or system search.
- Locate the existing ArrayListExamLab folder in the place where you created it.
- Select the ArrayListExamLab folder.
- Press Shift+Delete to delete the selected folder permanently.
- Approve the confirmation prompt.
- Return to the folder that contained ArrayListExamLab.
You should no longer see the ArrayListExamLab project folder.
Nice Work!
Nice Work!
You did it! Your console gradebook now demonstrates typed ArrayList operations through twelve passing checks.
You've learned how to:
- Build a typed gradebook that stores student names and scores in matching order.
- Diagnose the integer removal trap by proving how index removal differs from value removal.
- Verify collection behavior with a plain Java PASS/FAIL harness that tests reusable generic methods for printing, swapping, and finding the largest value.
- Secret Mission: Extended the lab with a generic reverse algorithm that reverses any typed ArrayList in place by reusing swap().
Ready to quiz yourself?