Java Basics Applied Class

exercises
tutorial
java
recursion
control-flow

Applied class exercises for week 2, reviewing week 1’s 2026-02-26-course-overview-and-java-basics content (switch statements, arrays, recursion). Meant to be done without a computer — you’re welcome to look up Java/library information, but your group knowing the answer isn’t a substitute for individual competence.

On the HTML site, fill in each blank with your answer (as a quoted string, e.g. "46368"), then click Run Code to check it. In the PDF, the Working callout is shown as a static answer key instead (interactive checking needs a browser).

Question 1 — Numbers to Numbers

Implement a method, nameOf, with the signature public static String nameOf(int value). If 0 < value < 10, return the name of the number, otherwise return "??".

What does each call return?

nameOf(4)

nameOf(7)

nameOf(24)

Task 0 — using switch:

public static String nameOf(int value) {
    return switch (value) {
        case 1 -> "One";
        case 2 -> "Two";
        case 3 -> "Three";
        case 4 -> "Four";
        case 5 -> "Five";
        case 6 -> "Six";
        case 7 -> "Seven";
        case 8 -> "Eight";
        case 9 -> "Nine";
        default -> "??";
    };
}

The modern -> switch expression syntax is preferred over a traditional switch statement because it avoids one case accidentally falling through into the next if a break is omitted.

Task 1 — using an array of strings (with an early-exit variant):

public static String nameOf(int value) {
    if (value <= 0 || value >= 10) {
        return "??";
    }
    String[] numbers = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
    return numbers[value - 1];
}

Bonus — extending to 10-99, using tiered helpers:

/** Requires: value > 0 && value < 10 **/
private static String ones(int value) {
    String[] numbers = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
    return numbers[value - 1];
}

/** Requires: value >= 10 && value < 20 **/
private static String teens(int value) {
    String[] numbers = {"Ten", "Eleven", /* ... */};
    return numbers[value - 10];
}

/** Requires: value >= 20 && value < 100 **/
private static String tens(int value) {
    String[] numbers = {"Twenty", "Thirty", /* ... */};
    return numbers[value / 10 - 2];
}

public static String nameOf(int value) {
    if (value > 0 && value < 10) {
        return ones(value);
    }
    if (value >= 10 && value < 20) {
        return teens(value);
    }
    if (value >= 20 && value < 100) {
        if (value % 10 == 0) {
            return tens(value);
        } else {
            return tens(value) + " " + ones(value % 10);
        }
    }
    return "??";
}

Question 2 — Fibonacci Sequence

The Fibonacci sequence (\(0, 1, 1, 2, 3, \ldots\)) is defined as \(\mathcal{F}(0)=0\), \(\mathcal{F}(1)=1\), \(\mathcal{F}(n) = \mathcal{F}(n-1) + \mathcal{F}(n-2)\) for \(n \geq 2\): 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...

Implement public static int fib(int n), returning the \(n\)th element. What is fib(24)?

public static int fib(int n) {
    if (n <= 1) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}

Desk check (manual, pen-and-paper trace of the recursive calls) for fib(6):

graph RL
    F6["F(6)"] -->|5| F5["F(5)"]
    F6 -->|3| F4a["F(4)"]
    F5 -->|3| F4b["F(4)"]
    F5 -->|2| F3a["F(3)"]
    F4a -->|2| F3b["F(3)"]
    F4a -->|1| F2a["F(2)"]
    F4b -->|2| F3c["F(3)"]
    F4b -->|1| F2b["F(2)"]
    F3a -->|1| F2c["F(2)"]
    F3a -->|1| F1a["F(1)"]
    F3b -->|1| F2d["F(2)"]
    F3b -->|1| F1b["F(1)"]
    F3c -->|1| F2e["F(2)"]
    F3c -->|1| F1c["F(1)"]
    F2a -->|1| F1d["F(1)"]
    F2a -->|0| F0a["F(0)"]
    F2b -->|1| F1e["F(1)"]
    F2b -->|0| F0b["F(0)"]
    F2c -->|1| F1f["F(1)"]
    F2c -->|0| F0c["F(0)"]
    F2d -->|1| F1g["F(1)"]
    F2d -->|0| F0d["F(0)"]
    F2e -->|1| F1h["F(1)"]
    F2e -->|0| F0e["F(0)"]

Question 3 — The Collatz Conjecture

Start with any positive integer \(n\): if even, divide by 2; if odd, multiply by 3 and add 1; repeat. The (unproven, but checked below \(2075 \times 2^{60}\) as of 2025) conjecture is that this always reaches 1.

Implement public static int collatz(int n), returning the number of steps to reach 1. What is collatz(3)?

public static int collatz(int n) {
    int steps = 0;
    while (n != 1) {
        if (n % 2 == 0) {
            n = n / 2;
        } else {
            n = 3 * n + 1;
        }
        steps++;
    }
    return steps;
}

Trace for collatz(3): 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1, which is 7 steps.

Question 4 — Ackermann function (extra)

The Ackermann–Péter function: \(\mathcal{A}(m,n) = n+1\) if \(m=0\); \(\mathcal{A}(m-1, 1)\) if \(m>0, n=0\); \(\mathcal{A}(m-1, \mathcal{A}(m, n-1))\) if \(m>0, n>0\).

Implement public long ackermann(short m, short n), and explain why it takes short parameters but returns a long.

public long ackermann(short m, short n) {
    if (m == 0) {
        return n + 1;
    }
    if (m > 0 && n == 0) {
        return ackermann((short) (m - 1), (short) 1);
    }
    if (m > 0 && n > 0) {
        return ackermann((short) (m - 1),
                          (short) ackermann(m, (short) (n - 1)));
    }
    return -1; // Impossible case but required for coverage.
}

Note the explicit (short) casts on every recursive call — Java’s arithmetic (m - 1, n - 1) implicitly promotes short operands to int, so without the casts this wouldn’t compile against a short-typed parameter.

Why short in, long out? The Ackermann function grows extremely rapidly even for small inputs, so the parameters are restricted to short (deliberately small inputs) while the result is a long, so the (much larger) output can be represented without overflow.