Original (poorly documented code that needs improvement:)


// Does stuff with numbers
public int doSomething(int[] nums) {
    int result = 0;
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] > 0 && nums[i] % 2 == 0) {
            result += nums[i];
        }
    }
    return result;
}

Proper Javadoc:


/**
 * Computes the sum of all positive even integers in the input array.
 * <p>
 * Iterates over {@code nums} and accumulates values that are strictly greater than zero
 * and divisible by two without remainder. Returns the total of those values.
 * </p>
 *
 * <h3>Preconditions</h3>
 * <ul>
 *   <li>{@code nums} is not {@code null}.</li>
 * </ul>
 *
 * <h3>Postconditions</h3>
 * <ul>
 *   <li>Returns the sum of all elements e in {@code nums} where {@code e > 0 && e % 2 == 0}.</li>
 *   <li>Returns {@code 0} if no elements satisfy the condition.</li>
 * </ul>
 *
 * @param nums the array to scan (non-null). May contain negative values and zeros.
 * @return the sum of positive even integers in {@code nums}
 *
 * <h3>Example</h3>
 * <pre>
 * int[] a = { -3, -2, 0, 1, 2, 4, 5 };
 * int s = doSomething(a);  // s == 6
 * </pre>
 */
public int doSomething(int[] nums) {
    int result = 0;
    for (int i = 0; i < nums.length; i++) {
        int val = nums[i];
        if (val > 0 && val % 2 == 0) {
            result += val;
        }
    }
    return result;
}

Popcorn Hack 2


import java.util.*;

/**
 * GradeBook manages assignments grouped by category and computes a weighted final grade.
 * <p>
 * Each category (e.g., Homework, Tests) has a weight in the range {@code [0.0, 1.0]}.
 * Assignments are stored as scores in {@code [0.0, 100.0]} and averaged per category.
 * The final grade is the weighted sum of category averages, plus optional extra credit.
 * Weights do not have to sum to 1.0; if they do not, they are normalized internally.
 * </p>
 *
 * <h3>Example</h3>
 * <pre>
 * GradeBook gb = new GradeBook();
 * gb.setCategoryWeight("Homework", 0.30);
 * gb.setCategoryWeight("Tests", 0.70);
 * gb.addAssignment("Homework", "HW1", 95.0);
 * gb.addAssignment("Tests", "Unit1", 88.0);
 * gb.setExtraCredit(2.5);
 * double finalGrade = gb.calculateFinalGrade(); // ~90.1
 * System.out.println(gb.generateReport());
 * </pre>
 *
 * @author Your
 * @version 1.0
 * @since 2025-10-13
 */
public class GradeBook {

    /**
     * assignments: category -> (assignmentName -> score)
     */
    private final Map<String, Map<String, Double>> assignments = new HashMap<>();

    /**
     * categoryWeights: category -> weight in [0,1]
     */
    private final Map<String, Double> categoryWeights = new HashMap<>();

    /**
     * Extra credit points added after weighted grade (not capped; caller may cap externally).
     */
    private double extraCredit = 0.0;

    /**
     * Adds or updates an assignment score in a category.
     *
     * <h3>Preconditions</h3>
     * <ul>
     *   <li>{@code category} non-null, non-empty</li>
     *   <li>{@code name} non-null, non-empty</li>
     *   <li>{@code score} in {@code [0.0, 100.0]}</li>
     * </ul>
     *
     * <h3>Postconditions</h3>
     * <ul>
     *   <li>Assignment stored under {@code category} with the given {@code name} and {@code score}.</li>
     *   <li>Existing assignment with the same name is overwritten.</li>
     * </ul>
     *
     * @param category the category (e.g., "Homework")
     * @param name     assignment identifier (e.g., "HW1")
     * @param score    the score in [0, 100]
     * @throws IllegalArgumentException if inputs are invalid
     */
    public void addAssignment(String category, String name, double score) {
        validateNonEmpty(category, "category");
        validateNonEmpty(name, "name");
        if (score < 0.0 || score > 100.0) {
            throw new IllegalArgumentException("score must be in [0, 100]");
        }
        assignments.computeIfAbsent(category, k -> new LinkedHashMap<>()).put(name, score);
    }

    /**
     * Sets the weight for a category.
     *
     * <h3>Preconditions</h3>
     * <ul>
     *   <li>{@code category} non-null, non-empty</li>
     *   <li>{@code weight} in {@code [0.0, 1.0]}</li>
     * </ul>
     *
     * @param category the category name (e.g., "Tests")
     * @param weight   weight in [0.0, 1.0]
     * @throws IllegalArgumentException if inputs are invalid
     */
    public void setCategoryWeight(String category, double weight) {
        validateNonEmpty(category, "category");
        if (weight < 0.0 || weight > 1.0) {
            throw new IllegalArgumentException("weight must be in [0, 1]");
        }
        categoryWeights.put(category, weight);
    }

    /**
     * Sets extra credit to add after weighted grade.
     *
     * @param points extra credit points (can be negative to remove points)
     */
    public void setExtraCredit(double points) {
        this.extraCredit = points;
    }

    /**
     * Calculates the final grade as the normalized weighted sum of category averages plus extra credit.
     * <p>
     * If the sum of provided weights is zero, unweighted average of all assignments is returned
     * (plus extra credit). Empty GradeBook returns 0.0 + extra credit.
     * </p>
     *
     * @return final grade in percentage (not automatically bounded to [0, 100])
     */
    public double calculateFinalGrade() {
        // Aggregate category averages
        Map<String, Double> categoryAverages = new HashMap<>();
        for (Map.Entry<String, Map<String, Double>> e : assignments.entrySet()) {
            String category = e.getKey();
            Collection<Double> scores = e.getValue().values();
            if (scores.isEmpty()) continue;
            double sum = 0.0;
            for (double s : scores) sum += s;
            categoryAverages.put(category, sum / scores.size());
        }

        if (categoryAverages.isEmpty()) {
            return 0.0 + extraCredit;
        }

        // Weighted calculation
        double weightSum = 0.0;
        for (double w : categoryWeights.values()) weightSum += w;

        double result;
        if (weightSum > 0.0) {
            double weightedSum = 0.0;
            for (Map.Entry<String, Double> e : categoryAverages.entrySet()) {
                String category = e.getKey();
                double avg = e.getValue();
                double w = categoryWeights.getOrDefault(category, 0.0);
                weightedSum += avg * w;
            }
            // Normalize by total specified weight (only categories with weights contribute)
            result = weightedSum / weightSum + extraCredit;
        } else {
            // No weights: average across all assignments
            double total = 0.0;
            int count = 0;
            for (Map<String, Double> m : assignments.values()) {
                for (double s : m.values()) {
                    total += s;
                    count++;
                }
            }
            result = (count == 0 ? 0.0 : total / count) + extraCredit;
        }
        return result;
    }

    /**
     * Produces a formatted multi-line report with categories, assignments, averages, weights, and final grade.
     *
     * @return a human-readable report
     */
    public String generateReport() {
        StringBuilder sb = new StringBuilder();
        sb.append("=== GradeBook Report ===\n");
        for (String category : new TreeSet<>(assignments.keySet())) {
            sb.append("- Category: ").append(category)
              .append(" (weight=").append(categoryWeights.getOrDefault(category, 0.0)).append(")\n");
            Map<String, Double> items = assignments.get(category);
            double sum = 0.0;
            for (Map.Entry<String, Double> e : items.entrySet()) {
                sb.append("  • ").append(e.getKey()).append(": ").append(e.getValue()).append("\n");
                sum += e.getValue();
            }
            if (!items.isEmpty()) {
                sb.append("  Avg: ").append(sum / items.size()).append("\n");
            }
        }
        double finalGrade = calculateFinalGrade();
        sb.append("Extra Credit: ").append(extraCredit).append("\n");
        sb.append("Final Grade: ").append(finalGrade).append("\n");
        return sb.toString();
    }

    private static void validateNonEmpty(String s, String field) {
        if (s == null || s.trim().isEmpty()) {
            throw new IllegalArgumentException(field + " must be non-empty");
        }
    }
}

---

Homework Assignment

/* Original Code
public class stuff{
public static void main(String args[]){
int x=5;
int y=10;
int z=add(x,y);
System.out.println("ans is "+z);
}

static int add(int a,int b){
return a+b;
}
}
*/

Improved Version with Javadoc and Style Fixes


/**
 * Demonstrates basic integer addition by invoking a helper method.
 * <p>
 * This class defines {@code add(int, int)} and shows how to call it from {@code main}.
 * </p>
 *
 * @author Student
 * @version 1.0
 * @since 2025-10-13
 */
public class Calculator {

    /**
     * Entry point. Creates two integers, adds them, and prints the result.
     *
     * @param args command-line arguments (unused)
     */
    public static void main(String[] args) {
        int x = 5;
        int y = 10;
        int z = add(x, y);
        System.out.println("The answer is " + z);
    }

    /**
     * Adds two integers.
     *
     * @param a first addend
     * @param b second addend
     * @return {@code a + b}
     */
    static int add(int a, int b) {
        return a + b;
    }
}

Homework Assignment p2

/**
 * Attempts to enroll a student in a course for a specified semester.
 * <p>
 * Validates student existence, course existence, seat availability, schedule conflicts,
 * prerequisites, and the 18-credit maximum. If all checks pass, links the student and course
 * and records an enrollment transaction.
 * </p>
 *
 * <h3>Preconditions</h3>
 * <ul>
 *   <li>{@code studentId} refers to an existing student.</li>
 *   <li>{@code courseCode} refers to an existing course.</li>
 *   <li>{@code semester} is a valid semester identifier understood by the system.</li>
 *   <li>Student is not already enrolled in {@code courseCode} for {@code semester}.</li>
 * </ul>
 *
 * <h3>Postconditions</h3>
 * <ul>
 *   <li>On success: the student is added to the course roster; the course is added to the student's schedule; an enrollment transaction is recorded.</li>
 *   <li>On any validation failure: no changes are made to student or course records.</li>
 * </ul>
 *
 * @param studentId unique identifier of the student
 * @param courseCode unique code of the course
 * @param semester semester number or code
 * @return {@code true} if enrollment succeeds; {@code false} otherwise
 *
 * <h3>Example</h3>
 * <pre>
 * boolean ok = enrollStudent("S12345", "CS101", 1);
 * System.out.println(ok ? "Enrollment successful" : "Enrollment failed");
 * </pre>
 */
public boolean enrollStudent(String studentId, String courseCode, int semester) {
    Student student = findStudentById(studentId);
    if (student == null) return false;

    Course course = findCourseByCode(courseCode);
    if (course == null) return false;

    if (course.isFull()) return false;
    if (student.hasScheduleConflict(course)) return false;
    if (!student.hasPrerequisites(course)) return false;
    if (student.getCreditHours() + course.getCreditHours() > 18) return false;

    student.addCourse(course);
    course.addStudent(student);
    recordEnrollmentTransaction(studentId, courseCode, semester);
    return true;
}

HW p3

Part 3: Reflection Questions

Question 1: Why is documentation more important in team projects than solo projects?

Documentation helps teammates understand what your methods do, what inputs they expect, and what could go wrong. When new people join the team, they can read the docs instead of bugging everyone. In solo projects, you might remember what you did, but in teams, nobody can read your mind

Question 2: Give an example of when a method SHOULD be documented and when it SHOULD NOT.

SHOULD document: Methods with tricky logic, specific requirements, or non-obvious behavior. Like a method that calculates weighted grades with multiple parameters and formulas - you need to explain what each parameter does and how the calculation works.

SHOULD NOT document: simple getters and setters like getName() or setAge(). If the method name already tells you everything, don’t waste time documenting it.


/**
 * Calculates compound interest: A = P (1 + r/n)^(n t).
 *
 * <h3>Preconditions</h3>
 * <ul>
 *   <li>{@code principal} > 0</li>
 *   <li>{@code rate} in [0, 1]</li>
 *   <li>{@code time} > 0</li>
 *   <li>{@code compoundsPerYear} >= 1</li>
 * </ul>
 *
 * @return final amount after compounding
 */
public double calculateCompoundInterest(double principal, double rate, double time, int compoundsPerYear) {
    return principal * Math.pow(1 + rate / compoundsPerYear, compoundsPerYear * time);
}

// Trivial: documentation unnecessary
public String getName() { return name; }
public void setAge(int age) { this.age = age; }

---

Fixing the Compilation Errors

public class StudentProfile {
    private String name;

    /**
     * Validates and normalizes the student's name.
     * Trims whitespace, converts to Proper Case, and ensures allowed characters only.
     *
     * @param name the proposed name
     * @throws IllegalArgumentException if null/empty or contains invalid characters
     */
    public void setNameWithValidation(String name) {
        if (name == null || name.trim().isEmpty()) {
            throw new IllegalArgumentException("Name cannot be null or empty");
        }
        String trimmed = name.trim();
        if (!trimmed.matches("[A-Za-z' -]+")) {
            throw new IllegalArgumentException("Invalid characters in name");
        }
        this.name = normalizeName(trimmed);
    }

    public String getName() {
        return name;
    }

    // Helper to convert to Proper Case (first letter uppercase for each token)
    private String normalizeName(String s) {
        String[] parts = s.toLowerCase().split("\\s+");
        StringBuilder out = new StringBuilder();
        for (int i = 0; i < parts.length; i++) {
            if (parts[i].isEmpty()) continue;
            String p = parts[i];
            out.append(Character.toUpperCase(p.charAt(0))).append(p.substring(1));
            if (i < parts.length - 1) out.append(" ");
        }
        return out.toString();
    }
}

---

Extra credit


/**
 * Computes the factorial of {@code n} recursively.
 *
 * <h3>Definition</h3>
 * n! = n × (n-1)!, with 0! = 1 and 1! = 1
 *
 * <h3>Preconditions</h3>
 * <ul>
 *   <li>{@code n} >= 0</li>
 *   <li>Result fits in {@code long}; no overflow checks are performed</li>
 * </ul>
 *
 * <h3>Postconditions</h3>
 * <ul>
 *   <li>Returns n! as {@code long}</li>
 * </ul>
 *
 * <h3>Complexity</h3>
 * <ul>
 *   <li>Time: O(n)</li>
 *   <li>Space: O(n) recursion depth</li>
 * </ul>
 */
public long factorial(int n) {
    if (n < 0) throw new IllegalArgumentException("n must be non-negative");
    if (n <= 1) return 1L;           // base case
    return n * factorial(n - 1);     // recursive case
}

---

Challenge 2

Team Documentation Standard (v1.0)

When to Document

  • Document: complex logic, invariants, pre/postconditions, side effects, performance tradeoffs, non-obvious error handling.
  • Do not document: trivial getters/setters; obvious control flow.
  • Update docs with every code change that alters behavior.

Required Tags by Method Type

  • General methods: @param (each), @return (if non-void), @throws (for checked and meaningful unchecked)
  • Public API: include usage example and constraints
  • Utilities with tricky behavior: include edge cases and complexity notes

Templates

  • Method Template: /**
    • Brief summary (what/why).
    • Longer details if needed.

    • Preconditions:
    • Postconditions:
    • @param …
    • @return …
    • @throws …
    • example

      */

  • Class Template: /**
    • Purpose and responsibilities.
    • Usage example.
    • Notes on design decisions.
    • @author …
    • @version …
    • @since … */

Common Mistakes

  • Vague phrases (“processes data”).
  • Missing edge cases (nulls, empties).
  • Outdated docs after refactors.
  • Over-documenting obvious code.