Numbers, Triangles, and Tables: Mastering Loops (Java)

Numbers, Triangles, and Tables: Mastering Loops (Java)

Here’s something most programming courses don’t tell you upfront: you’ll spend the rest of your career writing loops. For loops, while loops, iterator patterns—they’re fundamental to everything you’ll build. This lab isn’t about making something flashy. It’s about getting so comfortable with loops that you stop thinking about the syntax and start thinking about the patterns.

Why This Lab Matters

This feels like a simple assignment. Generate some numbers, print some asterisks, make a multiplication table. And yeah, on the surface, that’s what it is. But here’s what you’re actually learning:

Loop Mechanics: You need to understand exactly when a loop starts, when it ends, what happens in each iteration, and how variables change over time. Get this wrong and you’ll debug off-by-one errors for the rest of your life.

String Building: Real programs generate output constantly—reports, logs, formatted data, user interfaces. This lab teaches you how to build strings programmatically, which is something you’ll do daily in any development job.

Pattern Recognition: Triangles and tables aren’t random exercises. They’re patterns. Learning to see the pattern behind the visual output is the skill that lets you translate business requirements into code.

Return vs. Print: One of the most important lessons here is understanding the difference between returning a value and printing it. Methods that return values are composable, testable, and reusable. Methods that print directly are none of those things.

The Three Challenges

You’re building three utility classes. Each one focuses on a different aspect of loop mastery:

1. NumberUtilities: Counting and Generating

Generate sequences of numbers based on different rules:

  • Even numbers in a range
  • Odd numbers in a range
  • Squared values with a step
  • Custom ranges with step values
  • Exponentiation patterns

What you’re learning: Basic loop iteration, conditional logic inside loops, and numeric operations.

2. TriangleUtilities: Pattern Building

Generate ASCII triangle patterns of different sizes:

  • Single rows of asterisks
  • Small triangles (4 rows)
  • Large triangles (10 rows)
  • Custom-sized triangles

What you’re learning: Nested loops, visual pattern generation, and building output incrementally.

3. TableUtilities: Formatted Output

Create multiplication tables with proper formatting:

  • Small tables (4×4)
  • Large tables (10×10)
  • Custom-sized tables with alignment

What you’re learning: Nested loops with dual variables, string formatting, and producing structured output.

The Critical Concept: Return vs. Print

Let me emphasize this because it trips up every beginner:

Your methods must RETURN strings, not print them.

Here’s why this matters:

 1// Bad: Prints directly
 2public static void getEvenNumbersBad(int start, int stop) {
 3    for (int i = start; i < stop; i++) {
 4        if (i % 2 == 0) {
 5            System.out.println(i);  // Can't test this, can't compose it
 6        }
 7    }
 8}
 9
10// Good: Returns a string
11public static String getEvenNumbers(int start, int stop) {
12    String result = "";
13    for (int i = start; i < stop; i++) {
14        if (i % 2 == 0) {
15            result += i;
16        }
17    }
18    return result;  // Testable, composable, reusable
19}

When you return values, your code becomes a building block. When you print directly, you’ve created a dead end.

Phase-by-Phase Implementation

Phase 1: Simple Number Sequences

Start with the easiest challenge: generating even and odd numbers.

 1public static String getEvenNumbers(int start, int stop) {
 2    // Generate even numbers from start to stop (exclusive)
 3    String result = "";
 4    for (int num = start; num < stop; num++) {
 5        if (num % 2 == 0) {
 6            result += num;
 7        }
 8    }
 9    return result;
10}

Think about:

  • What does a for loop with num < stop actually give you?
  • How do you check if a number is even? (Hint: modulo operator)
  • Do we need to convert the number to a string before concatenating?
  • What happens if there are no even numbers in the range?

Test it:

1System.out.println(getEvenNumbers(5, 20));  // Should output: "681012141618"
2System.out.println(getEvenNumbers(10, 15)); // Should output: "1012"

Common mistakes:

  • Including stop in the loop (remember, we use < not <=)
  • Testing for odd when you meant even (or vice versa)
  • Forgetting that Java concatenation auto-converts primitives to strings

Phase 2: Loops with Steps and Operations

Now level up with squares and exponentiation:

1public static String getSquareNumbers(int start, int stop, int step) {
2    // Generate squared values with a step
3    String result = "";
4    for (int num = start; num < stop; num += step) {
5        int squared = num * num;
6        result += squared;
7    }
8    return result;
9}

Think about:

  • How does the step parameter change the iteration?
  • When do you calculate the square—before or after the loop check?
  • Could you use Math.pow(num, 2) instead of num * num? (Yes, but multiplication is faster)

Test it:

1System.out.println(getSquareNumbers(5, 15, 5));  // Should output: "25100"
2System.out.println(getSquareNumbers(1, 5, 1));   // Should output: "1491625"

Phase 3: Building Visual Patterns

Triangles are where loops get interesting. You need to think in two dimensions:

 1public static String getRow(int width) {
 2    // Generate a row of asterisks
 3    String result = "";
 4    for (int i = 0; i < width; i++) {
 5        result += "*";
 6    }
 7    return result;
 8}
 9
10public static String getTriangle(int n) {
11    // Generate an n-row triangle
12    String result = "";
13    for (int i = 1; i <= n; i++) {
14        result += getRow(i) + "\n";
15    }
16    return result;
17}

Think about:

  • Why does the loop use i <= n instead of i < n?
  • What’s the pattern between row number and number of asterisks?
  • Why add \n after each row?
  • How does getRow() make getTriangle() simpler?

Test it:

1System.out.println(getTriangle(4));
2// Should output:
3// *
4// **
5// ***
6// ****

This is decomposition in action. You break the problem into smaller pieces. getRow() handles one row. getTriangle() handles multiple rows by calling getRow() repeatedly. This is how you manage complexity.

Phase 4: Nested Loops and Formatting

Multiplication tables require nested loops—a loop inside a loop:

 1public static String getMultiplicationTable(int width) {
 2    // Generate a multiplication table of given width
 3    String result = "";
 4    for (int row = 1; row <= width; row++) {
 5        for (int col = 1; col <= width; col++) {
 6            int product = row * col;
 7            result += String.format("%3d |", product);
 8        }
 9        result += "\n";
10    }
11    return result;
12}

Think about:

  • Why do you need TWO loops?
  • What does the outer loop represent? The inner loop?
  • What’s happening with String.format("%3d |", product)? (Right-align in 3 characters)
  • Why add the newline after the inner loop finishes?

Test it:

1System.out.println(getMultiplicationTable(3));
2// Should output:
3//   1 |  2 |  3 |
4//   2 |  4 |  6 |
5//   3 |  6 |  9 |

The nested loop pattern:

  • Outer loop: controls rows
  • Inner loop: controls columns
  • After inner loop completes: move to next row

This pattern shows up everywhere: processing 2D arrays, generating grids, working with matrices, building tables in web apps.

String Building Strategies

You have multiple ways to build strings in Java. Know them all:

String Concatenation (Simple but works)

1String result = "";
2for (int i = 0; i < 5; i++) {
3    result += i;
4}

Pros: Easy to understand, works everywhere
Cons: Can be slow for very large strings (creates new string each time)

StringBuilder (Efficient and recommended)

1StringBuilder sb = new StringBuilder();
2for (int i = 0; i < 5; i++) {
3    sb.append(i);
4}
5String result = sb.toString();

Pros: Much faster for large strings, mutable
Cons: Slightly more verbose

String.format (For formatting)

1String result = "";
2for (int i = 0; i < 5; i++) {
3    result += String.format("%d", i);
4}

Pros: Clean syntax, supports formatting
Cons: Overhead for simple concatenation

For this lab, simple concatenation works fine for small strings. For production code with large strings or many concatenations, use StringBuilder. The important thing is understanding what you’re doing, not memorizing “the right way.”

Common Pitfalls and How to Avoid Them

1. Off-by-One Errors

The classic loop mistake. Remember: for (int i = start; i < stop; i++) goes UP TO but NOT INCLUDING stop.

1// Wrong: Misses the last number you want
2for (int i = 1; i < 10; i++) {  // Goes 1-9, not 1-10
3    System.out.println(i);
4}
5
6// Right: Use <= if you want to include the end
7for (int i = 1; i <= 10; i++) {  // Goes 1-10
8    System.out.println(i);
9}

2. String Concatenation Performance

For loops with many iterations, string concatenation can be slow:

 1// Works but slow for large loops
 2String result = "";
 3for (int i = 0; i < 10000; i++) {
 4    result += i;  // Creates new string each time
 5}
 6
 7// Better for large loops
 8StringBuilder sb = new StringBuilder();
 9for (int i = 0; i < 10000; i++) {
10    sb.append(i);  // Modifies existing buffer
11}
12String result = sb.toString();

3. Printing Instead of Returning

Your tests will fail if you print instead of return:

 1// Wrong: Tests can't capture this
 2public static void getEvenNumbers(int start, int stop) {
 3    for (int i = start; i < stop; i++) {
 4        if (i % 2 == 0) {
 5            System.out.println(i);  // Goes to console, not to caller
 6        }
 7    }
 8}
 9
10// Right: Tests can verify this
11public static String getEvenNumbers(int start, int stop) {
12    String result = "";
13    for (int i = start; i < stop; i++) {
14        if (i % 2 == 0) {
15            result += i;
16        }
17    }
18    return result;  // Caller receives the value
19}

4. Not Understanding Nested Loops

Each iteration of the outer loop runs the ENTIRE inner loop:

1for (int row = 0; row < 3; row++) {        // Runs 3 times
2    for (int col = 0; col < 4; col++) {    // Runs 4 times PER row
3        System.out.println(row + ", " + col);
4    }
5}
6// Total iterations: 3 × 4 = 12

If you’re confused about what’s happening, add print statements to see the iteration count:

1int iteration = 0;
2for (int row = 0; row < 3; row++) {
3    for (int col = 0; col < 4; col++) {
4        iteration++;
5        System.out.printf("Iteration %d: row=%d, col=%d%n", iteration, row, col);
6    }
7}

Testing Your Code

The repository comes with tests. Here’s how to use them effectively:

Java:

1cd java
2mvn test

Reading test failures:

When a test fails, it tells you:

  • What method was being tested
  • What input was provided
  • What output was expected
  • What output you actually returned

Use this information to debug. Don’t just stare at your code—look at what the test expected and compare it to what you returned.

Testing incrementally:

Don’t write all three utilities and then test. Write one method, test it, make it pass, then move to the next. This is how professionals work.

The Bigger Picture

These exercises might seem basic, but they’re teaching you patterns you’ll use constantly:

Number generation → Database queries returning ranges, pagination, batch processing

Triangle patterns → Understanding nested structures, building UI components, generating reports

Multiplication tables → Formatting data for display, building grids, creating structured output

Six months from now, you won’t be making multiplication tables. But you WILL be using nested loops to process data, format output, and generate structured information. The patterns are the same.

Going Further (Optional Extensions)

Once you’ve got the basics working, try these challenges:

Advanced Number Utilities

  • Generate prime numbers in a range
  • Create Fibonacci sequences
  • Generate numbers in different bases (binary, hexadecimal)

Pattern Variations

  • Right-aligned triangles
  • Inverted triangles
  • Diamond patterns
  • Hollow triangles (asterisks only on edges)

Table Enhancements

  • Addition tables, not just multiplication
  • Custom operators (subtraction, division)
  • Formatted decimal alignment
  • Color-coded output (for terminal apps)

The Professional Mindset

Here’s what this lab is really teaching:

Precision: Loops require exact thinking. Off by one? Wrong output. Wrong condition? Infinite loop. This precision is what separates working code from broken code.

Decomposition: Breaking problems into smaller methods. getRow() helps build getTriangle(). This is how you manage complexity in real systems.

Testability: Returning values instead of printing makes your code testable. Tests are how professional teams ensure code quality.

Pattern Recognition: Seeing the loop pattern behind the visual output. This skill translates directly to translating business requirements into code.

Getting Started

Here’s your action plan:

  1. Clone the repository from https://github.com/ZCW-Summer25/NumbersTrianglesTables
  2. Choose your language (Java or Python) and navigate to that directory
  3. Start with NumberUtilities: Get comfortable with basic loops
  4. Move to TriangleUtilities: Practice nested loops and patterns
  5. Finish with TableUtilities: Master two-dimensional iteration
  6. Run tests frequently: Don’t wait until everything is done
  7. Experiment: Once tests pass, try the optional extensions

Remember: Loops Are Forever

You will write loops in every program you create for the rest of your career. Getting comfortable with them now—understanding how they work, what patterns they follow, and how to debug them—is time incredibly well spent.

Don’t rush through this. Take the time to understand each loop’s behavior. Print intermediate values. Draw diagrams of what’s happening. The investment you make now in truly understanding loops will pay off every single day you write code.

ℹ️
Repository Link Find the starter code and complete instructions at: https://github.com/ZCW-Summer25/NumbersTrianglesTables