Programming Bootcamp
Introduction to Programming

What is Programming?

Learn how computers think, what programming languages are, and how code goes from human-readable text to something a CPU can actually run.

🖥️ Hardware 💡 Concepts 🌐 Languages 🚀 Hello World
Lesson 1 — Section 1: Hardware

What Does a Computer Actually Do?

At its core, every computer has three key parts that work together.

🧠

CPU

The brain. Performs calculations and runs instructions — billions per second. Think of it as a chef following a recipe.

RAM

Short-term memory. Super fast, but temporary — everything in RAM disappears when you turn off the computer.

💾

Storage (SSD/HDD)

Long-term memory. Slower, but permanent — where your files and programs live when not running.

🎮 Think about it: When you open a game, it travels from Storage → RAM → CPU. The CPU runs the game logic; RAM keeps the current state; Storage holds saved files.
Lesson 1 — Section 1: Hardware

How the CPU Runs Instructions

The CPU repeats this cycle billions of times per second. It's fast, not smart.

📥 FETCH Get next instruction from RAM 🔍 DECODE Figure out what it means (add, jump...) EXECUTE Do the instruction, store the result ...repeat billions of times/sec
🤖 Key insight: Computers are fast, not smart. They mindlessly repeat this loop, doing exactly what they're told. If you write the wrong instruction — you get the wrong result.
Lesson 1 — Section 1: Hardware

Software = A List of Instructions

A program is just a very long, very precise recipe for the computer to follow.

🍕 Pizza Recipe 1 Make the dough 2 Add sauce 3 Add toppings 4 Bake at 220°C 5 Enjoy! 🎉

📋 Programs are recipes

Just like a recipe, skip a step or do them out of order and you get something unexpected — or nothing at all!

🐛 Bugs = wrong instructions

Computers do exactly what you tell them. Bugs happen because you wrote the wrong step — not because the computer made a mistake.

🎯 Precision matters

Every comma, bracket, and letter counts. Programming teaches you to think clearly and precisely.

Lesson 1 — Section 1: Hardware

The OS: The Middleman

Your program never talks directly to hardware. There's a layer in between — the Operating System.

Your Program (Java, Python, a game, a browser...) asks the OS for help Operating System 🪟 Windows 🍎 macOS 🐧 Linux talks to drivers & hardware Hardware 🧠 CPU ⚡ RAM 💾 Storage 🖥️ Display println() → OS → driver → screen

🧱 What the OS does

Manages CPU time, RAM, storage, and devices so multiple programs can share hardware without crashing into each other.

🤝 Why you don't have to worry

When Java prints to the screen, it asks the OS, which tells the display driver, which controls the monitor. Java handles this chain — you just write println().

Lesson 1 — Section 2: Programming Languages

Why Do Programming Languages Exist?

CPUs only understand 0s and 1s — programming languages bridge the gap between humans and machines.

Binary 01001000 01100101 01101100 01101100... Assembly MOV EAX, 1 ADD EAX, EBX C Language int x = a + b; printf("%d", x); ☕ Java int x = a + b; System.out.println(x); ← Human readable! ← harder to read · more control easier to read · more abstraction →

☕ Java was born in 1995

Created by James Gosling at Sun Microsystems to solve a big problem: code written for one OS wouldn't run on another.

✈️ Write Once, Run Anywhere

Java compiles to bytecode, which the JVM (Java Virtual Machine) can run on any computer — Windows, Mac, Linux.

🌍 Used Everywhere

Android apps, Minecraft, bank systems, government software — and it's the language used in AP Computer Science A!

Lesson 1 — Section 2: Programming Languages

Java: A Hybrid Approach

Different languages take different paths to the CPU. Java's approach is a middle ground — next slide we'll compare it to C and Python.

✏️ Main.java You write this javac ⚙️ Main.class Bytecode file JVM 🖥️ JVM Translates per OS Your CPU Runs the program! 🪟 Windows 🍎 Mac 🐧 Linux "Write Once, Run Anywhere"
💡 Java doesn't compile to raw machine code (like C) and isn't interpreted line-by-line (like Python). It hits a middle point: bytecode that any machine can run as long as it has a JVM installed — "Write Once, Run Anywhere."
Lesson 1 — Section 2: Programming Languages

How Different Languages Reach Your CPU

C, Python, and Java each take a completely different path from source code to running program.

C hello.c gcc hello.exe Native machine code ⚡ CPU Fast. But tied to one OS. Python hello.py interpreter Read line by line No compile step! ⚡ CPU Easy to run. Slower at runtime. Java Main.java javac Main.class Bytecode (portable) JVM JVM Translates per OS ⚡ CPU Portable. Middle-ground speed.

C — Native Compile

Fastest at runtime. Compiles to machine code your OS runs directly. Not portable — you recompile per platform.

Python — Interpreted

No compile step. The interpreter reads and runs each line. Great for quick scripts; slower at runtime than compiled languages.

Java — Bytecode + JVM

Compiles once to portable bytecode. The JVM handles the final step on each platform. Best of both worlds for most use cases.

Lesson 1 — Section 2: Types of Languages

Compiled vs. Interpreted

How does code actually run? Two very different approaches.

📦

Compiled — C, Java, Go

The entire program is translated before it runs. The compiler checks for errors first — nothing runs until it's clean.

source compile binary run Output

✅ Catches errors early · Often faster

📜

Interpreted — Python, JavaScript

Instructions are read and run one line at a time as the program executes. More flexible, but errors only show up when that line runs.

code.py line by line Interpreter Out

✅ Easier to test · No compile step

🤔 Think: Which catches mistakes earlier — compiled or interpreted? Compiled! The compiler checks everything before a single line runs.
Lesson 1 — Section 2: Types of Languages

Static vs. Dynamic Typing

Java makes you label what type of data a variable holds. Python figures it out on the fly.

☕ Java — Statically Typed

int score = 100; String name = "Jesus"; double price = 9.99; boolean isWinner = true; // ❌ This won't even compile: int x = "hello";

You must declare the type. The compiler enforces it before running.

🐍 Python — Dynamically Typed

score = 100 name = "Jesus" price = 9.99 is_winner = True # This is fine in Python: x = "hello" x = 42 # type changed!

No type labels needed. More flexible but errors show up later.

😤 Heads up: Java's strictness will feel annoying at first — but it catches entire categories of bugs before your program even runs. It makes you a more precise thinker.
Lesson 1 — Section 2: Errors

The Three Types of Errors

You will see all three this course. Here's what each one means.

🚫

Compile-Time Error

Caught before the program runs. Java won't even create a .class file. Syntax mistakes, type mismatches.

Easiest to fix — the compiler points right at it.

💥

Runtime Error

The program starts, but crashes mid-run. Examples: dividing by zero, accessing something that doesn't exist.

The error message shows where it crashed.

🤡

Logic Error

The program runs fine and produces output — but the output is wrong. Nothing tells you something broke.

Hardest to find — requires testing and thinking.

🧠 Remember: Getting errors is normal. Every programmer gets them every day. The skill is learning to read them and fix them.
Lesson 1 — Section 3: A First Look at Java

What Java Code Looks Like

We'll set up and run this in Lesson 4 — for now, let's read it and understand every piece.

public class Main { public static void main(String[] args) { System.out.println("Hello, World!"); } }
public class Main — defines a class. All Java code lives inside a class. The file must be named Main.java.
public static void main — the entry point. Java always starts here when you run a program.
System.out.println() — prints a line to the console. Verbose? Yes. You'll type it hundreds of times and it becomes second nature!
{ } — curly braces define the boundaries of a class or method. Everything inside belongs to it.
Lesson 1 — Section 3: A First Look at Java

From Code to Output — Conceptually

You don't need to run this yet. Just understand the journey a Java program takes.

✏️ You write Main.java javac ⚙️ Compiler produces Main.class (bytecode) JVM 🖥️ JVM runs it on your OS 🖨️ Hello, World! printed to screen
📌 Coming in Lesson 4: We'll install Java, set up our editor, and actually run this. For now the important thing is understanding what each step does — not the commands themselves.
Lesson 2 — Variables & Data Types

Variables & Data Types

How programs remember information — and why the type of data matters.

score 100 int name "Jesus" String gpa 3.8 double isWinner true boolean RAM — labeled boxes holding values
📦 Variables 🔢 Primitives 🧮 Arithmetic 🔤 Strings
Lesson 2 — Variables

What is a Variable?

A variable is a named slot in RAM that your program can read or change while it runs.

RAM score 0 lives 3 playerName "Alex" isGameOver false Each box has a name, a type, and a value

Three things every variable has

Name — what you call it (score, lives)
Type — what kind of data it holds
Value — the actual data inside

Naming rules

Use camelCase: playerScore, isGameOver. Can't start with a number. Can't use Java keywords like int or class.

Values can change

That's why they're called variables. A game score starts at 0 and goes up — same box, different value each time.

Lesson 2 — Variables

The Four Core Primitive Types

Java has 8 primitive types — these four cover nearly everything you'll need.

🔢

int

Whole numbers. Scores, counts, ages.

int score = 100; int lives = 3;

⚠️ 7 / 2 gives 3, not 3.5 — decimals get chopped!

🌡️

double

Decimal numbers. Prices, averages, measurements.

double gpa = 3.8; double price = 9.99;

8 bytes; tiny rounding quirks at extreme precision.

boolean

Exactly two values: true or false.

boolean isWinner = true; boolean gameOver = false;

Powers every if statement and loop you'll ever write.

🔤

char

A single character in single quotes.

char grade = 'A'; char init = 'J';

Single quotes = char. Double quotes = String.

Lesson 2 — Variables

The String Type

String is not a primitive — it's a class. But it's so essential it gets its own slide.

String name = "Jesus"; String greeting = "Hello, " + name; // greeting = "Hello, Jesus" String msg = "Score: " + 42; // msg = "Score: 42" // ⚠️ Watch out: String tricky = "1" + 2 + 3; // tricky = "123", not 6!

Concatenation with +

The + operator joins strings together. Mix a String with any other type and Java converts it automatically.

Capital S matters

String is capitalized because it's a class, not a primitive. Java is case-sensitive — string won't work.

Comparing Strings

Never use == to compare Strings. Use .equals() instead. We'll cover why in Lesson 9.

Lesson 2 — Variables

Declaring, Assigning & Printing

Three things you'll do with every variable — understand the difference between each.

// Declaration — reserves the box int score; // Initialization — puts a value in score = 0; // Both at once (most common) int lives = 3; // Reassignment — change the value lives = 2; // no "int" keyword again! // Print a variable System.out.println(lives); // 2 System.out.println("Lives: " + lives); // Lives: 2

Declaration vs. Initialization

Declaration creates the box. Initialization puts something in it. Java will error if you try to use a variable before it has a value.

Common mistake

Writing int lives = 2; a second time causes "variable already defined." Drop the type keyword on reassignment.

println vs. print

println adds a newline at the end. print doesn't — useful for printing things side by side.

Lesson 2 — Variables

Arithmetic Operators

Same math you know — with a few programming twists.

int a = 10, b = 3; System.out.println(a + b); // 13 System.out.println(a - b); // 7 System.out.println(a * b); // 30 System.out.println(a / b); // 3 ← not 3.33! System.out.println(a % b); // 1 ← remainder // Force decimal division: System.out.println(10.0 / b); // 3.333... // Shortcuts a += 5; // a = a + 5 → 15 a++; // a = a + 1 → 16

⚠️ Integer division

10 / 3 gives 3 — the decimal is thrown away. Make one number a double to get 3.333.

% — The Remainder

10 % 3 = 1 because 10 ÷ 3 = 3 remainder 1. Classic use: n % 2 == 0 checks if a number is even.

Shortcuts save typing

+= -= *= and ++ / -- are everywhere in Java code — get comfortable with them now.

Lesson 2 — Operators Deep Dive

Increment (++) & Decrement (--)

The most common shortcuts in Java — used everywhere. Master these and you'll recognize half the code you see.

int lives = 3; // Post-increment (++ after) System.out.println(lives++); // prints 3 System.out.println(lives); // prints 4 // Pre-increment (++ before) System.out.println(++lives); // prints 5 // Decrement (same idea) System.out.println(lives--); // prints 5 System.out.println(--lives); // prints 3 // Usually in a loop: for (int i = 0; i < 5; i++) { System.out.println(i); }

Post-increment (x++)

Uses the current value first, then increments. Like: "use it, then bump it."

int x = 5; int y = x++; // y = 5, x = 6

Pre-increment (++x)

Increments first, then uses the new value. Like: "bump it, then use it."

int x = 5; int y = ++x; // y = 6, x = 6

The practical difference

In loops, it doesn't matter — i++ and ++i do the same thing. But when assigning: y = x++ behaves very differently from y = ++x!

Lesson 2 — Operators Deep Dive

Compound Assignment Operators

These combine an operation and an assignment into one shorthand — they're everywhere in real code.

int score = 100; // Compound assignments score += 10; // same as: score = score + 10 score -= 5; // same as: score = score - 5 score *= 2; // same as: score = score * 2 score /= 4; // same as: score = score / 4 score %= 3; // same as: score = score % 3 // Practical example: health bar int health = 100; health -= 25; // take damage System.out.println(health); // 75

Why use them?

Shorter to write and read. Compare: playerScore += 50 vs. playerScore = playerScore + 50. The first is clearer and faster to type.

Works with all basic operators

+= -= *= /= %=
Each one is equivalent to: x = x ⊕ value

Game dev example

Increment a counter, decrement health, multiply by a power-up multiplier. These shortcuts make game logic clean and readable.

Lesson 2 — Operators Deep Dive

Modulus (%) — The Remainder Operator

The most underrated operator. It's not just for math class — it's essential for real-world programming problems.

// Basic examples System.out.println(10 % 3); // 1 System.out.println(20 % 7); // 6 System.out.println(15 % 5); // 0 // Check if even or odd int num = 17; if (num % 2 == 0) { System.out.println("Even"); } else { System.out.println("Odd"); } // Cycle through values (wrapping) int day = 7; int nextDay = (day % 7) + 1; // if day = 7 (Saturday), nextDay = 1

What % really does

10 % 3 asks: "If I divide 10 by 3, what's left over?" Answer: 10 = (3 × 3) + 1 → remainder is 1.

Real-world uses

Even/odd check: n % 2 == 0
Every nth iteration: if (i % 5 == 0) runs every 5 steps
Wrapping indices: (index % arrayLength)

Game dev example

A deck of cards cycles: cardIndex % 52 wraps back to card 0 after card 51. A timer loop: frame % 10 triggers every 10 frames.

Lesson 2 — Practice

Operator Cheat Sheet & Common Patterns

A quick reference for everything you've learned about operators — use this as a bookmark!

Increment & Decrement

int x = 5;
x++ → use, then +1
++x → +1, then use
x-- → use, then -1
--x → -1, then use

Compound Assignment

All equivalent to: x = x ⊕ value

+= add
-= subtract
*= multiply
/= divide
%= mod

Modulus Patterns

n % 2 == 0 even?
n % 2 == 1 odd?
i % 5 == 0 every 5th?
index % size wrap around
Pro tip: These operators will feel awkward at first. But by Lesson 4 (loops), you'll use i++ dozens of times per program. Comfort comes with repetition.
Lesson 2 — Arrays

What is an Array?

So far we've stored one value per variable. But what if we need 100 test scores or a deck of 52 cards? Enter arrays.

scores array (int[]) [0] 85 [1] 92 [2] 78 [3] 88 ... scores (the array name) One variable holds many values ❌ Without arrays: int score1, score2, score3... (tedious!) ✅ With arrays: int[] scores (clean!)

Arrays hold multiple values

Same type, accessed by index (position). scores[0] is the first value, scores[1] is the second.

Index starts at 0

This is crucial — the first element is always at index 0, not 1. A common source of "off-by-one" bugs!

Fixed size

When you create an array, you decide how many slots it has. You can't add more later (not in this course, anyway).

Single type

An int[] holds only integers. A String[] holds only strings.

Lesson 2 — Arrays

Creating Arrays

The syntax looks odd at first, but you'll type it hundreds of times and it becomes automatic.

// Declare and create (empty) int[] scores = new int[5]; // 5 slots, all start at 0 // Declare and initialize (with values) int[] grades = {85, 92, 78, 88}; // 4 slots with specific values // For Strings String[] names = {"Alice", "Bob", "Carol"}; // For booleans boolean[] flags = new boolean[10]; // 10 slots, all start as false // Get the length int size = grades.length; // 4

The [] syntax

Read "int square-bracket" as "array of int." The [] goes after the type, not the variable name.

Using new

The new keyword creates the array in RAM. The number in brackets is the size.

Default values

int[] → 0, double[] → 0.0, boolean[] → false, String[] → null

The .length property

Every array has a .length (not a method!). Perfect for loops: i < array.length

Lesson 2 — Arrays

Using Arrays — Getting & Setting Values

You access elements by index — the same syntax you saw in the diagrams.

int[] scores = {85, 92, 78}; // GET (read) a value int first = scores[0]; // 85 int second = scores[1]; // 92 int last = scores[2]; // 78 // SET (write) a value scores[0] = 90; // change first to 90 scores[1]++; // increment second to 93 // Print individual elements System.out.println(scores[0]); // 90 System.out.println(scores[1]); // 93 // Use a variable as index int idx = 2; System.out.println(scores[idx]); // 78

Index must exist

If the array has 3 elements (indices 0, 1, 2), asking for scores[3] crashes with ArrayIndexOutOfBoundsException.

Use expressions as indices

You can use variables, math, or even method calls inside brackets: scores[i+1] or scores[random()].

Arrays are mutable

Once created, you can change individual elements as many times as you want, but you can't resize the array.

Arrays with indices

This is why loops exist! In Lesson 2, you'll loop through arrays with for (int i = 0; i < scores.length; i++).

Lesson 2 — Arrays

Arrays: Quick Reference

A cheat sheet for everything arrays. Bookmark this one!

Declaration Patterns

int[] whole numbers
double[] decimals
String[] text
boolean[] true/false

Key Facts

  • 📍 0-indexed: First element is [0], last is [length - 1]
  • 📍 Fixed size: Declared once, can't grow or shrink
  • 📍 .length property: Always tells you the size
  • 📍 Mutable: Change elements, not the array itself
🔗 Why arrays matter: You can't meaningfully loop through data without arrays. Lesson 2 will teach you loops — and arrays + loops are where programming gets powerful. Master this foundation now!
Lesson 3 — Input & Decisions

Getting Input & Making Decisions

Programs become useful when they can react to the user — read what they type and decide what to do next.

⌨️

Scanner

Read what the user types from the keyboard.

🔀

if / else

Run different code depending on a condition.

⚖️

Comparison operators

Compare values: equal, greater, less than.

🔗

Logical operators

Combine conditions: AND, OR, NOT.

Lesson 3 — Input

Reading User Input with Scanner

The Scanner class lets your program pause and wait for the user to type something.

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Enter your name: "); String name = sc.nextLine(); System.out.print("Enter your age: "); int age = sc.nextInt(); System.out.println("Hi " + name + ", you are " + age + "!"); } }

import statement

Scanner lives in the java.util package. You must import it at the top before you can use it.

Reading different types

nextLine() → String
nextInt() → int
nextDouble() → double

System.in

Just like System.out sends to the screen, System.in reads from the keyboard.

Lesson 3 — Decisions

if / else if / else

The most fundamental decision-making tool in any programming language.

int score = 85; if (score >= 90) { System.out.println("A"); } else if (score >= 80) { System.out.println("B"); } else if (score >= 70) { System.out.println("C"); } else { System.out.println("Study more!"); } // Prints: B
score = 85 ≥ 90? no yes → "A" ≥ 80? print "B" yes no → ... "A"
Java checks conditions top to bottom and stops at the first one that's true.
Lesson 3 — Decisions

Comparison & Logical Operators

These are the building blocks of every condition you'll ever write.

Comparison operators — return true or false

int x = 5; x == 5 // true — equal to x != 3 // true — not equal to x > 3 // true — greater than x < 3 // false — less than x >= 5 // true — greater or equal x <= 4 // false — less or equal

Logical operators — combine conditions

int age = 17; boolean hasTicket = true; // AND — both must be true age >= 18 && hasTicket // false // OR — at least one true age >= 18 || hasTicket // true // NOT — flips true/false !hasTicket // false
🧠 Memory trick: && = AND (both), || = OR (either), ! = NOT (flip it). You read ! as "not" — so !isGameOver means "game is not over."
Lesson 3 — Mini-Project

Mini-Project: Number Guessing Game

Putting it all together — Scanner + if/else in one small program.

import java.util.Scanner; public class GuessingGame { public static void main(String[] args) { int secret = 42; Scanner sc = new Scanner(System.in); System.out.print("Guess a number: "); int guess = sc.nextInt(); if (guess == secret) { System.out.println("🎉 Correct!"); } else if (guess < secret) { System.out.println("Too low!"); } else { System.out.println("Too high!"); } } }

What this uses

Variables (int secret, int guess), Scanner to read input, and if/else to react.

What's missing?

The player only gets one chance. In Lesson 4 we'll add a loop so they can keep guessing until they get it right.

Challenge: extend it

Can you modify it to also tell the player how far off their guess was? Hint: subtraction and Math.abs().

Mini-Project Setup — Step 1 of 3

Open Terminal & Set Up Java

We'll use Terminal to create the project folder, then use mise to pin Java 21 to it.

① Open Terminal

Press ⌘ Space, type Terminal, press Enter. A black or white window with a command prompt opens.

② Jump to labs & create the lab1 folder

labs mkdir lab1 cd lab1

labs is your alias for ~/Development/labs. mkdir lab1 creates this lab's folder, and cd lab1 moves you into it. Your prompt should now end with lab1.

③ Pin Java 21 to this project with mise

mise use java@21

This creates a .mise.toml file in your project folder that tells mise which Java version to use here. If Java 21 isn't installed yet, mise will install it automatically.

④ Confirm Java is ready

java --version

You should see:

openjdk 21.0.x 2024-...

If you see a different version or an error, make sure you ran cd into the project folder first.

Mini-Project Setup — Step 2 of 3

Open VS Code & Create the File

Still in Terminal — one command opens the whole project in VS Code.

① Open VS Code from Terminal

code .

The . means "this folder." VS Code opens with lab1 loaded in the Explorer panel on the left.

② Create GuessingGame.java

In VS Code's Explorer panel (left sidebar), hover over the folder name and click the New File icon (📄). Type GuessingGame.java and press Enter.

③ Paste in the code

Click inside the new file and paste the GuessingGame code from the previous slide. Save with ⌘ S.

VS Code will highlight the code with colors — that's syntax highlighting telling you the code was parsed correctly.

lab1 — VS Code
📁 lab1
📄 GuessingGame.java
📄 .mise.toml
public class GuessingGame {
public static void main(...) {
// your code here
}
}
Notice the .mise.toml file mise created — it locks Java 21 to this project so anyone who opens it gets the right version automatically.
Mini-Project Setup — Step 3 of 3

Run It in VS Code

The Java extension adds a ▶ Run button above your main method — no terminal commands needed.

① Click ▶ Run above main

Look just above the line public static void main — VS Code shows a small ▶ Run link. Click it. VS Code compiles and runs your program automatically.

② The Terminal panel opens

VS Code opens the integrated terminal at the bottom of the screen and runs your program there. You'll see the prompt Guess a number: — click in the terminal and type your guess.

③ Prefer the command line? That works too

Open the terminal with ⌃ ` and run it yourself:

javac GuessingGame.java java GuessingGame
Terminal (inside VS Code)
# VS Code ran this for you automatically:
~/Development/labs/lab1 $ java GuessingGame
Guess a number:
20
Too low!
Guess a number:
60
Too high!
Guess a number:
42
🎉 Correct!
🎉 Your first real Java program — running on your Mac.
Recap — Lessons 1, 2 & 3

What You've Covered

🖥️

Lesson 1 — How Computers Work

CPU, RAM, Storage, the OS layer. Fetch-Decode-Execute cycle. Programming languages bridge humans and binary. C, Python, Java each take a different path to the CPU.

📦

Lesson 2 — Variables & Data Types

Variables are named RAM slots. Primitives: int, double, boolean, char. Strings concatenate with +. Integer division truncates. % gives the remainder.

🔀

Lesson 3 — Input & Decisions

Scanner reads from the keyboard. if/else if/else branches on a condition. Comparison operators produce booleans. && / || / ! combine them.

🚀

Coming Up — Lesson 4

Loops — while, do-while, for, and for-each — and we'll finally set up Java and run real code.

Lesson 4 — Control Flow & Repetition

Loops

Computers are great at repeating things — millions of times without getting tired. Loops are how you tell them to do it.

condition still true? run the block false → stop
🔁 while 🔄 do-while 🔢 for ⛔ break & continue
Lesson 4 — while & do-while

Why Repetition Matters

Without loops, you'd have to write the same line of code thousands of times. Loops let you say it once and let the computer repeat it.

😩 Without a loop — printing 1 to 5:

System.out.println(1); System.out.println(2); System.out.println(3); System.out.println(4); System.out.println(5); // What if you needed 1 to 1,000,000?

✅ With a loop — same result, one idea:

int i = 1; while (i <= 5) { System.out.println(i); i++; } // Change 5 to 1_000_000 — done.
🎮

Game loops

Every game runs a loop — check input, update state, draw screen — thousands of times per second.

📋

Processing data

Go through every student's grade, every order in a store, every message in an inbox.

Waiting for input

Keep asking the user for a valid answer until they give one — a natural loop.

Lesson 4 — while loop

The while Loop

Repeat a block of code as long as a condition stays true. Check the condition before each iteration.

// Anatomy of a while loop while ( condition ) { // body — runs if condition is true // must eventually make condition false! } // Example: count down from 5 int count = 5; while (count > 0) { System.out.println(count); count--; // ← moves toward false } System.out.println("Blast off! 🚀");
Output: 5 → 4 → 3 → 2 → 1 → Blast off! 🚀
count = 5 count > 0 ? true println(count) count-- loop back false Blast off! 🚀
Lesson 4 — do-while loop

The do-while Loop

Like a while loop — but the body runs at least once before the condition is ever checked.

// Anatomy do { // body runs first, THEN condition checked } while ( condition ); // ← note semicolon! // Great for: "ask until valid" Scanner sc = new Scanner(System.in); int guess; do { System.out.print("Enter 1–10: "); guess = sc.nextInt(); } while (guess < 1 || guess > 10); System.out.println("Valid: " + guess);
The user must type something before we can check if it's valid — do-while is the natural fit here.

while — checks first

If the condition starts false, the body never runs. Use when you might not need to run at all.

do-while — runs first

Body always runs at least once, then checks. Use when you need to do something before you can decide to continue.

Real-world examples

Menu systems, input validation, game rounds — anywhere the user must act before the program can decide what to do next.

Lesson 4 — Common Bugs

Two Classic Loop Bugs

These will happen to you. Knowing what they look like makes them easy to fix.

🔴 Infinite Loop — never stops

int i = 1; while (i <= 5) { System.out.println(i); // ❌ forgot i++ ! } // prints 1 forever...

Symptoms

Program runs forever, terminal freezes, fan spins up. Fix: press ⌃ C to stop it, then make sure the loop variable actually changes inside the body.

🟡 Off-by-One — one too many or few

// Want to print 1 through 5 int i = 1; while (i < 5) { // ❌ should be <= System.out.println(i); i++; } // only prints 1 2 3 4 — misses 5! // Fix: while (i <= 5) { ... } // ✅

Symptoms

Loop runs one iteration too many or too few. Often caused by using < when you needed <= (or vice versa). Extremely common — even experienced developers make this mistake.

Lesson 4 — Exercise

Exercise: Guessing Game with Retries

Update your guessing game so the player can keep guessing until they get it right.

import java.util.Scanner; public class GuessingGame { public static void main(String[] args) { int secret = 42; Scanner sc = new Scanner(System.in); int guess = 0; int attempts = 0; while (guess != secret) { System.out.print("Guess: "); guess = sc.nextInt(); attempts++; if (guess < secret) System.out.println("Too low!"); else if (guess > secret) System.out.println("Too high!"); } System.out.println( "🎉 Got it in " + attempts + " tries!"); } }

What changed from Lesson 3?

Added a while loop around the guess logic. The loop keeps running until guess == secret.

Tracking attempts

attempts++ increments a counter each iteration — the loop naturally counts how many tries it took.

Challenge

Add a max of 7 guesses. If the player doesn't guess in 7 tries, reveal the answer. Hint: add && attempts < 7 to the condition.

Lesson 4 — for loop

The for Loop

When you know exactly how many times to repeat, for packs the setup, condition, and update into one tidy line.

for ( int i = 0 ① init ; i < 5 ② condition ; i++ ③ update ) { println(i); ④ body }
// Print 0 through 4 for (int i = 0; i < 5; i++) { System.out.println(i); } // Output: 0 1 2 3 4 // Count down for (int i = 10; i >= 1; i--) { System.out.print(i + " "); } // Output: 10 9 8 7 6 5 4 3 2 1 // Count by 2s for (int i = 0; i <= 10; i += 2) { System.out.print(i + " "); } // Output: 0 2 4 6 8 10

① Init — runs once

Creates the loop variable before the first iteration. Usually int i = 0. The variable only exists inside the loop.

② Condition — checked before each iteration

If false, the loop ends immediately. Same as a while loop's condition.

③ Update — runs after each iteration

Usually i++ to move forward, but can be any expression — i--, i += 2, etc.

Lesson 4 — for vs while

When to Use for vs while

Both can do the same job — but one is usually a better fit depending on what you know upfront.

🔢

Use for when you know the count

You know exactly how many times to loop — iterating over a list, counting from A to B, repeating N times.

// Print a 5-star rating for (int i = 0; i < 5; i++) { System.out.print("⭐"); } // Sum 1 through 100 int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } System.out.println(sum); // 5050

Use while when count is unknown

You don't know how many times — keep going until some event happens (user input, a condition changes, a file ends).

// Keep asking until "quit" String input = ""; while (!input.equals("quit")) { System.out.print("Command: "); input = sc.nextLine(); } // Read a file line by line while (scanner.hasNextLine()) { process(scanner.nextLine()); }
Lesson 4 — Nested Loops

Nested Loops

A loop inside a loop. The inner loop runs completely for every single iteration of the outer loop.

// Times table (1–5) for (int row = 1; row <= 5; row++) { for (int col = 1; col <= 5; col++) { System.out.printf("%4d", row * col); } System.out.println(); }
1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
col=1 col=2 col=3 col=4 col=5 row=1 row=2 row=3 row=4 row=5 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
For a 5×5 grid: outer runs 5 times, inner runs 5 times per outer iteration = 25 total executions of the body.
Lesson 4 — break & continue

break and continue

Two keywords that give you fine-grained control over what a loop does mid-iteration.

⛔ break — exit the loop immediately

// Stop when we find 7 for (int i = 1; i <= 10; i++) { if (i == 7) { System.out.println("Found 7!"); break; // jumps out of the loop } System.out.println(i); } // Output: 1 2 3 4 5 6 Found 7!

Use break when…

You found what you were looking for and there's no point continuing — searching a list, hitting a sentinel value, a game-over condition.

⏭️ continue — skip this iteration only

// Print only odd numbers for (int i = 1; i <= 10; i++) { if (i % 2 == 0) { continue; // skip evens } System.out.println(i); } // Output: 1 3 5 7 9

Use continue when…

You want to skip certain items but keep looping — filtering out invalid data, skipping blank lines, ignoring certain values in a calculation.

Lesson 4 — for-each

The for-each Loop

A cleaner syntax for looping over every item in a collection — no index variable needed.

// Regular for — needs index management int[] scores = {90, 85, 72, 95, 88}; for (int i = 0; i < scores.length; i++) { System.out.println(scores[i]); } // for-each — same result, cleaner for (int score : scores) { System.out.println(score); } // Read as: "for each score in scores" // Works on Strings too String[] names = {"Alice", "Bob", "Carol"}; for (String name : names) { System.out.println("Hello, " + name + "!"); }

Syntax: type variable : collection

The variable takes on each value in the collection one by one. You declare its type on the left side of the colon.

When to prefer for-each

When you just need each element's value and don't care about the index — reading, printing, summing, searching.

When to stick with for

When you need the index — modifying elements in place, going backwards, skipping by 2s, comparing adjacent elements.

Lesson 4 — Coding Exercise

FizzBuzz

A classic programming challenge. Simple rules, great practice for loops and conditions working together.

📋 The Rules

Write a program that prints every number from 1 to 100, but:

  • If the number is divisible by 3, print "Fizz" instead
  • If divisible by 5, print "Buzz" instead
  • If divisible by both, print "FizzBuzz"
  • Otherwise, just print the number

🧪 Expected output (first 20)

1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz

💡 Hint

Use the % (modulo) operator to check divisibility. n % 3 == 0 means n is divisible by 3. Check FizzBuzz first — order matters!

Your starter code:

public class FizzBuzz { public static void main(String[] args) { for (int i = 1; i <= 100; i++) { // your logic here } } }

🏆 Stretch challenges

1. Add a counter — print how many FizzBuzzes there were at the end
2. Make it go 1 to N where N is entered by the user (Scanner)
3. Add a 4th rule: divisible by 7 prints "Bazz"

📁 Create this in ~/Development/labs/lab2/ — use labsmkdir lab2 && cd lab2code .
Recap — Lesson 4

What You've Covered

🔁

while

Checks condition first. Runs zero or more times. Use when the count is unknown — keep going until something happens.

🔄

do-while

Runs the body first, then checks. Guarantees at least one execution. Ideal for input validation and menus.

🔢

for

Init, condition, update — all in one line. Use when you know the count. Can count up, down, or by any step size.

🗂️

for-each

Cleanest syntax for visiting every element in a collection. No index to manage — just the value.

🐛

Common bugs

Infinite loop — forgot to update the loop variable. Off-by-one — used < when you needed <=.

⛔⏭️

break & continue

break exits the loop entirely. continue skips the rest of this iteration and moves to the next.

🔲

Nested loops

Inner loop runs completely for each outer iteration. Total executions = outer count × inner count. Great for grids and tables.

🚀

Coming up — Lesson 5

Methods — breaking code into reusable named blocks, parameters, return types, and scope.

Lesson 5 — Methods

Methods

Stop repeating yourself. Package logic into a reusable, named block you can call again and again — with different data each time.

5, 3 parameters add(a, b) runs the same logic every time it's called 8 return value
📦 Define 📞 Call ➡️ Parameters ↩️ Return
Lesson 5 — Why Methods

Why We Break Code Into Methods

Without methods, every calculation gets copy-pasted everywhere you need it. Methods let you write the logic once.

😩 Without a method — repeated logic

int a = 5, b = 3; int sumOne = a + b; System.out.println(sumOne); int c = 10, d = 20; int sumTwo = c + d; // copy-pasted logic System.out.println(sumTwo); int e = 7, f = 1; int sumThree = e + f; // again! System.out.println(sumThree);

✅ With a method — write once, reuse

static int add(int x, int y) { return x + y; } // now just call it, with any numbers System.out.println(add(5, 3)); System.out.println(add(10, 20)); System.out.println(add(7, 1)); // one place to fix bugs, one place to improve
♻️

Reusability

Write the logic once, call it as many times as you need — with different data each time.

📖

Readability

A well-named method like calculateTax() explains itself — no comment needed.

🔧

Easier debugging

One bug in one place — fix it once and every caller benefits, instead of hunting down every copy.

Lesson 5 — Defining a Method

The Anatomy of a Method

Every method you write has the same five parts, no matter what it does.

static int ① return type add ② name ( int x, int y ③ parameters ) { return x + y; ④ body }
public class Main { // ⑤ defined once, outside main() static int add(int x, int y) { return x + y; } public static void main(String[] args) { int result = add(5, 3); System.out.println(result); // 8 } }

① Return type

What kind of value comes back out — int, double, String... or void if nothing comes back.

② Name

camelCase, just like variables. Should be a verb — add, calculateAverage, printReceipt.

③ Parameters

The inputs the method needs, in parentheses. Can be zero, one, or many — separated by commas.

④ Body

The code that runs when the method is called, wrapped in { }.

Lesson 5 — Calling Methods

Calling a Method

Defining a method doesn't run it — you have to call it by name for its code to execute.

main() add(5, 3); jumps into add(x, y) x = 5, y = 3 return x + y; → 8 returns 8, resumes println(result) prints: 8
static int add(int x, int y) { return x + y; } public static void main(String[] args) { System.out.println("Before call"); int result = add(5, 3); // ← call! System.out.println("After call: " + result); } // Before call // After call: 8

Call by name + parentheses

add(5, 3) pauses main, runs add's body completely, then main resumes exactly where it left off.

Lesson 5 — Parameters

Parameters — Passing Data In

Parameters let the same method work with completely different data every time it's called.

// Two parameters, both int static int multiply(int a, int b) { return a * b; } // Different types are fine too static void greet(String name, int age) { System.out.println("Hi " + name + ", age " + age); } greet("Jesus", 17); // "Jesus" → name, 17 → age (order matters!) greet(17, "Jesus"); // ❌ compile error — wrong order

Parameters vs. arguments

Parameters are the placeholders in the definition (int a, int b). Arguments are the real values you pass in when calling (5, 3).

Order matters

Arguments are matched to parameters by position, not by name. The 1st argument fills the 1st parameter, and so on.

Parameters are local

Inside the method, a and b behave like regular variables — you can even reassign them without affecting the caller's originals.

Lesson 5 — Return Types

Return Types — Sending Data Back

A method can hand a value back to whoever called it — or hand nothing back at all, using void.

Returns a value

static double average(int a, int b) { return (a + b) / 2.0; } double result = average(10, 5); System.out.println(result); // 7.5

Returns nothing — void

static void printReceipt(String item, double price) { System.out.println(item + ": $" + price); // no return statement needed } printReceipt("Coffee", 4.50);

return exits immediately

The moment Java hits return, the method ends — any code after it in that path never runs.

Type must match

If the method says int, you must return an int. Returning a String from an int method is a compile-time error.

void = side effects only

A void method does something (prints, changes something) but doesn't hand back a value you can store.

Every path must return

If a method promises int, every possible branch (if/else) must eventually hit a return — or it won't compile.

Lesson 5 — Scope

Scope: Local vs. Class-Level Variables

Where you declare a variable decides where it's visible — and where it disappears.

public class Main { // class-level (a "field") — visible to // every method in this class static int totalCalls = 0; static int square(int n) { int result = n * n; // ← local to square() totalCalls++; // ← field, shared return result; } public static void main(String[] args) { System.out.println(square(4)); System.out.println(result); // ❌ error: result // doesn't exist here! } }

Local variables

Declared inside a method. Only exist while that method is running — created fresh on each call, destroyed when it returns.

Class-level variables (fields)

Declared outside any method, directly in the class. Shared and visible across every method in that class.

Common mistake

Trying to use a local variable from one method inside a different method — Java says "cannot find symbol." It simply doesn't exist there.

Rule of thumb

Keep variables as local as possible. Only make something a field if multiple methods genuinely need to share it.

Lesson 5 — Recursion

Recursion — A Method That Calls Itself

A recursive method solves a problem by breaking it into a smaller version of the same problem, until it's simple enough to answer directly.

static int factorial(int n) { if (n <= 1) { return 1; // ① base case } return n * factorial(n - 1); // ② recursive case } System.out.println(factorial(4)); // factorial(4) = 4 * factorial(3) // = 4 * 3 * factorial(2) // = 4 * 3 * 2 * factorial(1) // = 4 * 3 * 2 * 1 // = 24
factorial(4) factorial(3) factorial(2) factorial(1) 🛑 base case → returns 1 unwinds, multiplying back up result = 24
🛑

① Base case

The simplest version of the problem, answered directly with no further recursive call. Without one, recursion never stops.

🔁

② Recursive case

Calls itself with a smaller or simpler input, moving one step closer to the base case each time.

📚

The call stack

Each call waits, paused, for the one below it to finish — then they all resolve in reverse order, like stacked plates.

Lesson 5 — Recursion

Recursion: Pitfalls & When to Use It

Recursion is elegant for the right problems — but a missing base case is the loop-forgot-to-update-i of recursion.

🔴 Missing base case — crashes

static int factorial(int n) { return n * factorial(n - 1); // ❌ no base case — never stops! } // Exception in thread "main" // java.lang.StackOverflowError

StackOverflowError

Recursion's version of an infinite loop. Each call takes up space on the call stack — with no base case, Java eventually runs out and crashes.

✅ Another example — countdown

static void countdown(int n) { if (n == 0) { System.out.println("Liftoff! 🚀"); return; // base case } System.out.println(n); countdown(n - 1); // moves toward 0 } // countdown(3) → 3, 2, 1, Liftoff! 🚀

Recursion vs. loops

Anything recursion can do, a loop can also do — and loops usually use less memory. Reach for recursion when a problem is naturally self-similar (folders inside folders, branches of a tree).

🧠 Checklist for every recursive method: Does it have a base case? Does every recursive call move closer to that base case? If either answer is no, you have an infinite recursion bug waiting to happen.
Lesson 5 — Mini-Project

Mini-Project: A Method-Powered Calculator

Rebuild a basic calculator, but this time every operation is its own method.

📋 The Requirements

Write four methods, each taking two double parameters and returning a double result:

  • add(a, b)
  • subtract(a, b)
  • multiply(a, b)
  • divide(a, b)

🧪 Expected output

10.0 + 4.0 = 14.0 10.0 - 4.0 = 6.0 10.0 * 4.0 = 40.0 10.0 / 4.0 = 2.5

💡 Hint

Call all four methods from main with the same two numbers, and print each labeled result with println.

Your starter code:

public class Calculator { static double add(double a, double b) { // your logic here } // define subtract, multiply, divide... public static void main(String[] args) { double x = 10, y = 4; // call each method and print the result } }

🏆 Stretch challenges

1. Add a modulus(a, b) method for the remainder
2. Guard divide against dividing by zero — print an error instead of crashing
3. Add a Scanner so the user types their own two numbers

📁 Create this in ~/Development/labs/lab3/ — use labsmkdir lab3 && cd lab3code .
Recap — Lesson 5

What You've Covered

♻️

Why methods

Write logic once, reuse it anywhere. Improves readability and makes bugs easier to fix — one place, not many.

📦

Defining

Return type, name, parameters, body — static <type> name(params) { }.

➡️

Parameters

Inputs passed by position. Local to the method — separate from the caller's original variables.

↩️

Return types

return sends a value back and exits immediately. void means no value comes back.

🔭

Scope

Local variables live and die inside one method call. Class-level fields are shared across every method.

🌀

Recursion

A method that calls itself needs a base case (stops it) and a recursive case (moves toward the base case).

🐛

StackOverflowError

Recursion's version of an infinite loop — a missing or unreachable base case means the calls never stop piling up.

🧮

Mini-project

Built a calculator with a dedicated method per operation — the same pattern real programs use everywhere.

🚀

Coming up — Lesson 6

ArrayLists — a resizable, more powerful alternative to arrays, plus the Collections framework.