Capstone Review and APE Preparation
Connecting all 10 weeks — from types to objects
After this lesson, you will be able to:
- Trace a multi-class Java program from file input through object creation, sorting, and output
- Identify which concept (types, control flow, arrays, I/O, OOP) applies to a given problem
- Write a complete integration program that combines all 10 weeks of material
- Prepare strategically for the final exam and the Advanced Proficiency Exam (APE)
Ten Weeks in One Question
Suppose someone hands you a CSV file of student records and says: “Read this data, sort the students by GPA, and write a formatted report to a new file.” To solve that, you need every single concept from this course: types to parse the data, control flow to loop through lines, arrays or ArrayLists to store objects, file I/O to read and write, classes to model a Student, and Comparable to define the sort order.
That is the point of this lesson. Not a single new concept — just the skill of combining everything you already know into a working program. This is what the final exam tests, what the APE tests, and what real-world programming demands.
From CSCD 110: In CSCD 110, you could read a file, loop through lines, split strings, and print output — all in about 15 lines of Python. Java requires more ceremony (type declarations, try/catch, class definitions), but the underlying logic is identical. The journey from Python to Java was never about learning new ideas. It was about learning to express the same ideas within a stricter type system. You now have that skill.
The Complete Toolkit: Quick Reference
Every major concept from Weeks 1–10 in one table. Use this as a checklist when studying.
| Theme | Concepts | Key Syntax | Common Traps |
|---|---|---|---|
| Types | int, double, boolean, char, String |
int x = 5; |
int division truncates; String is a reference |
| Casting | Widening (auto), narrowing (explicit) | (double) x, (int) y |
(double)(a/b) truncates first |
| Comparison | Primitives: ==; doubles: epsilon; Strings: .equals() |
Math.abs(a - b) < 1e-9 |
== on Strings compares addresses |
| Conditionals | if/else, switch, ternary, &&/|| |
if (x > 0) { } |
Chained comparisons invalid; missing break in switch |
| Loops | for, while, do-while |
for (int i = 0; i < n; i++) |
Off-by-one; fencepost errors |
| Methods | Parameters, return types, overloading, scope | public static int foo(final int n) |
Pass-by-value; scope dies at } |
| Arrays | Fixed-size, typed, 0-indexed | int[] a = new int[10]; |
No .add(); ArrayIndexOutOfBoundsException |
| ArrayList | Dynamic size, generic type | ArrayList<String> list = new ArrayList<>(); |
Cannot hold primitives directly; use wrapper types |
| File I/O | Scanner + File, PrintStream |
new Scanner(new File("data.txt")) |
Must handle FileNotFoundException |
| Exceptions | try/catch, checked vs unchecked |
try { } catch (Exception e) { } |
Catching too broadly hides bugs |
| Classes | Fields, constructors, getters, toString, equals |
public class Point { } |
Forgetting this.; public fields break encapsulation |
| Interfaces | Contracts, Comparable<T>, compareTo |
implements Comparable<Student> |
Return int, not boolean; sign matters |
| Sorting | Collections.sort(), Arrays.sort() |
Collections.sort(list); |
Class must implement Comparable |
| References | Stack vs heap, aliasing, null |
Point p = new Point(3, 4); |
== compares references; NullPointerException |
Theme 1: The Type System
The type system is the foundation of everything in Java. Every variable, every parameter, every return value has a declared type that the compiler enforces.
Primitives vs References:
Primitives (store values directly): References (store addresses):
int x = 42; String s = "hello";
double d = 3.14; int[] arr = new int[5];
boolean done = false; Student stu = new Student("Alice", 3.8);
char c = 'A';
The three comparison rules (these appear on every exam):
- Primitives (
int,double,char,boolean): use== - Floating-point precision: use
Math.abs(a - b) < epsilon - Objects (
String, arrays, your classes): use.equals()
Casting: Widening happens automatically (int to double). Narrowing requires an explicit cast and truncates: (int) 3.99 produces 3, not 4.
What does double result = (double)(7 / 2); assign to result?
Theme 2: Control Flow
Every program beyond “Hello, World” needs decisions and repetition.
Conditionals choose a path: if/else, switch, ternary. Loops repeat work: for (known count), while (unknown count), do-while (at least once).
The six accumulator patterns show up constantly:
| Pattern | Init | Update | Example Use |
|---|---|---|---|
| Counter | int count = 0; |
count++ |
How many even numbers? |
| Sum | int sum = 0; |
sum += value |
Total of all scores |
| Product | int prod = 1; |
prod *= value |
Factorial |
| Max | int max = Integer.MIN_VALUE; |
if (v > max) max = v; |
Highest score |
| Min | int min = Integer.MAX_VALUE; |
if (v < min) min = v; |
Lowest score |
| Flag | boolean found = false; |
found = true; |
Does a target exist? |
Methods encapsulate logic. Every method has a return type, a name, and parameters. Java is pass-by-value: a method gets a copy of each argument, so modifying a parameter inside a method does not change the caller’s variable.
Theme 3: Data Structures
Arrays are fixed-size, typed containers. You declare the size at creation and cannot change it:
int[] scores = new int[30]; // 30 slots, all initialized to 0
scores[0] = 95; // first element
scores[scores.length - 1] = 88; // last element
ArrayList is a resizable alternative that wraps an array internally:
ArrayList<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.remove(0); // removes "Alice"
System.out.println(names.size()); // 1
Arrays use [] and .length. ArrayLists use .get(), .set(), .add(), .remove(), and .size(). Arrays can hold primitives directly; ArrayLists require wrapper types (Integer, Double).
Theme 4: File I/O and Exceptions
Reading from a file uses Scanner with a File object. Writing uses PrintStream. Both require handling FileNotFoundException:
// Reading
Scanner input = new Scanner(new File("data.txt"));
while (input.hasNextLine()) {
String line = input.nextLine();
// process line
}
input.close();
// Writing
PrintStream output = new PrintStream(new File("report.txt"));
output.println("Header");
output.close();
Exception handling uses try/catch. The method signature declares checked exceptions with throws. Inside the method, try wraps risky code and catch handles failures gracefully instead of crashing.
Theme 5: Object-Oriented Programming
A class is a blueprint. An object is an instance of that blueprint. Encapsulation means fields are private and accessed through public methods (getters/setters).
Key methods every class should have:
- Constructor: initializes fields
- toString(): returns a human-readable representation
- equals(): compares logical equality (not reference identity)
- compareTo(): defines natural ordering (if the class implements
Comparable)
Interfaces define a contract. Comparable<T> requires a compareTo method that returns a negative integer, zero, or a positive integer. Once a class implements Comparable, you can sort collections of it with Collections.sort().
The Integration Example: Student Roster Application
This is the capstone pattern: read from file, create objects, sort, generate output. Every piece of the course contributes.
The Data File (students.csv)
Alice,1001,3.8
Bob,1002,3.2
Charlie,1003,3.5
Zoe,1005,3.8
Diana,1004,3.9
The Student Class
public class Student implements Comparable<Student> {
private String name;
private int id;
private double gpa;
public Student(final String name, final int id, final double gpa) {
this.name = name;
this.id = id;
this.gpa = gpa;
}
// Sort by GPA descending, then by name ascending as tiebreaker
public int compareTo(final Student other) {
int gpaResult = Double.compare(other.gpa, this.gpa);
if (gpaResult != 0) {
return gpaResult;
}
return this.name.compareTo(other.name);
}
public String getName() { return name; }
public int getId() { return id; }
public double getGpa() { return gpa; }
@Override
public String toString() {
return String.format("%s (ID: %d, GPA: %.2f)", name, id, gpa);
}
}
Notice what this class uses:
- Encapsulation: private fields, public getters
Comparable<Student>: the interface contractcompareTo: multi-field sorting (GPA first, name as tiebreaker)toString: formatted output withString.formatfinalparameters: Dr. Steiner’s convention
If Alice has GPA 3.8 and Zoe has GPA 3.8, what does alice.compareTo(zoe) return?
The Complete Main Program
This program ties together file I/O, object creation, sorting, and report generation:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class HonorRollReport {
public static void main(final String[] args) {
try {
// Step 1: Read students from CSV file
ArrayList<Student> students = readStudents("students.csv");
System.out.println("Read " + students.size() + " students.");
// Step 2: Sort by GPA (descending), then name
Collections.sort(students);
// Step 3: Print sorted list to console
System.out.println("\nSorted Student List:");
for (Student s : students) {
System.out.println(s);
}
// Step 4: Write formatted report to file
writeReport(students, "honor_roll.txt");
System.out.println("\nReport written to honor_roll.txt");
} catch (FileNotFoundException e) {
System.err.println("Error: " + e.getMessage());
}
}
/**
* Read student records from a CSV file.
* Format: name,id,gpa
*
* @param filename path to the CSV file
* @return list of Student objects
* @throws FileNotFoundException if the file does not exist
*/
public static ArrayList<Student> readStudents(final String filename)
throws FileNotFoundException {
ArrayList<Student> students = new ArrayList<>();
Scanner input = new Scanner(new File(filename));
while (input.hasNextLine()) {
String line = input.nextLine();
if (line.trim().isEmpty()) {
continue;
}
try {
String[] parts = line.split(",");
String name = parts[0].trim();
int id = Integer.parseInt(parts[1].trim());
double gpa = Double.parseDouble(parts[2].trim());
students.add(new Student(name, id, gpa));
} catch (NumberFormatException e) {
System.err.println("Warning: Bad data in line: " + line);
}
}
input.close();
return students;
}
/**
* Write a sorted honor roll report to a file.
*
* @param students sorted list of students
* @param filename output file path
* @throws FileNotFoundException if the file cannot be created
*/
public static void writeReport(final ArrayList<Student> students,
final String filename)
throws FileNotFoundException {
PrintStream output = new PrintStream(new File(filename));
output.println("=== HONOR ROLL REPORT ===");
output.println();
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
output.printf("%d. %s - GPA: %.2f%n", i + 1,
s.getName(), s.getGpa());
}
output.println();
output.println("Total Students: " + students.size());
double totalGpa = 0;
for (Student s : students) {
totalGpa += s.getGpa();
}
output.printf("Average GPA: %.2f%n", totalGpa / students.size());
output.close();
}
}
Output (console):
Read 5 students.
Sorted Student List:
Diana (ID: 1004, GPA: 3.90)
Alice (ID: 1001, GPA: 3.80)
Zoe (ID: 1005, GPA: 3.80)
Charlie (ID: 1003, GPA: 3.50)
Bob (ID: 1002, GPA: 3.20)
Report written to honor_roll.txt
Output (honor_roll.txt):
=== HONOR ROLL REPORT ===
1. Diana - GPA: 3.90
2. Alice - GPA: 3.80
3. Zoe - GPA: 3.80
4. Charlie - GPA: 3.50
5. Bob - GPA: 3.20
Total Students: 5
Average GPA: 3.64
Key Insight: This read-sort-process pipeline is the canonical pattern for real-world programs. Banking systems read transactions and generate statements. E-commerce platforms read orders and generate shipping lists. The data changes; the structure stays the same.
Concept Map: How Everything Connects
Types & Expressions
│
▼
Control Flow (if/else, loops)
│
▼
Methods (parameters, returns, scope)
│
├──────────────────┐
▼ ▼
Arrays / ArrayList File I/O (Scanner, PrintStream)
│ │
└────────┬─────────┘
▼
Classes & Objects (fields, constructors, encapsulation)
│
▼
Interfaces & Comparable (contracts, sorting)
│
▼
★ Integration: Read → Create → Sort → Report ★
Every level builds on the one above it. You cannot write the integration program without understanding all the layers.
APE Preparation Tips
The Advanced Proficiency Exam tests whether you can move directly into upper-division CS courses. Here is what to focus on:
What the APE tests:
- Code tracing (types, casting, expressions, method calls)
- Writing methods from descriptions (IPO: Input, Process, Output)
- Array and ArrayList manipulation (traversal, search, modification)
- Object-oriented design (classes, encapsulation,
toString,equals) - Interfaces and
Comparable(writingcompareTo, usingCollections.sort) - File processing (reading, parsing, exception handling)
Study strategy:
- Trace before you write. For every code example in this course, predict the output by hand before running it.
- Practice the patterns. Counter, sum, max, min, flag — you should be able to write these in your sleep.
- Write complete programs. The APE does not ask you to fill in blanks. It asks you to produce working code from scratch.
- Know the comparison rules. Primitives use
==. Strings use.equals(). Objects use.equals()or.compareTo(). Doubles use epsilon comparison. - Understand references. Know the difference between stack and heap. Know what aliasing means. Know when
==compares values and when it compares addresses.
You have a class Book that implements Comparable<Book> and an ArrayList<Book> books loaded from a file. Which single line sorts the list?
What Comes Next: CSCD 211
CSCD 211 (Programming Principles II) picks up exactly where this course ends. Here is what you will encounter:
- Inheritance and polymorphism: Extending classes, method overriding, the
superkeyword, abstract classes - Recursion: Methods that call themselves — the tree traversal pattern, divide-and-conquer algorithms
- Linked lists: Building your own data structure with nodes and references (no arrays)
- Stacks and queues: Abstract data types built on linked lists
- Generics: Writing classes that work with any type (
<T>) - Algorithm analysis: Big-O notation — measuring how fast code runs as input grows
Everything you learned here — types, control flow, arrays, file I/O, classes, interfaces — is prerequisite knowledge for CSCD 211. The better you understand this material, the smoother that transition will be.
Summary
This course took you from System.out.println("Hello, World!") to a multi-class application that reads files, creates objects, sorts them, and generates reports. The progression was deliberate:
- Weeks 1–2: Types, expressions, and the discipline of static typing
- Weeks 3–4: Control flow — making decisions and repeating work
- Week 5: Methods — decomposing problems into reusable pieces
- Week 6: Arrays — your first real data structure
- Week 7: File I/O — connecting programs to the outside world
- Weeks 8–9: Objects, classes, and interfaces — modeling the real world in code
- Week 10: Integration — combining all of the above into complete programs
The final exam and the APE test your ability to combine these tools. Study the patterns, trace code by hand, and practice writing complete programs. You have the toolkit. Now use it.