Java Calculator Application

In the last lesson you learned about Java ThreadLocal. Now let’s build something you can run and play with: a console calculator. It touches nearly everything you have learned, and we will grow it one piece at a time.

🎯 The problem we are solving

Picture a tiny on-screen calculator app. It asks “what do you want to do?”, takes two numbers, and prints the result. Doing it well means handling the messy parts.

  • The user might pick an option that does not exist.
  • They might try to divide by zero.
  • They might want many sums in a row without restarting.

So our goal is a calculator that keeps asking, handles bad choices calmly, never crashes on divide-by-zero, and exits only when the user says so.

Here is what our app will let the user do:

  • Pick an operation: add, subtract, multiply, divide, or exit.
  • Type two numbers.
  • See the result.
  • Repeat as many times as they like.
  • Exit cleanly when done.

We combine building blocks you already know:

  • A Scanner reads input.
  • A switch picks the math.
  • A loop keeps the menu coming back.

Let’s start with the menu.

🧱 Step 1: show a menu and read the choice

Before any math, the user needs to see their options. This code sets up the Scanner and prints the menu once.

import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("--- Simple Calculator ---");
System.out.println("1. Add (+)");
System.out.println("2. Subtract (-)");
System.out.println("3. Multiply (x)");
System.out.println("4. Divide (/)");
System.out.println("5. Exit");
System.out.print("Choose an option: ");
int choice = scanner.nextInt();
System.out.println("You chose: " + choice);
scanner.close();
}
}

Reading it from the top:

  • import java.util.Scanner lets us read keyboard input. Without it the Scanner name is unknown.
  • new Scanner(System.in) creates a reader on the keyboard. System.in is the standard input stream.
  • The println calls print each menu line. The last uses print (no line break) so typing sits right after the prompt.
  • scanner.nextInt() waits for a whole number and Enter, then stores it in choice.
  • scanner.close() releases the scanner when done.

That is the skeleton. Next we make it calculate.

🔢 Step 2: read two numbers

A calculator needs two numbers. We use double instead of int so it handles decimals like 3.5, not just whole numbers. This snippet reads the two values.

System.out.print("Enter first number: ");
double a = scanner.nextDouble();
System.out.print("Enter second number: ");
double b = scanner.nextDouble();

Things to notice:

  • nextDouble() reads a number that may have a decimal point. With nextInt(), typing 2.5 would crash the program.
  • Short names a and b are fine. Their job is obvious and they live only a few lines.
  • The prompts make it clear which number is which.

With the choice variable and the numbers in hand, we can do the math.

🔀 Step 3: pick the math with a switch

The user’s choice (1 to 4) tells us which operation to run. A switch is the cleanest tool. It checks one value against several cases and runs the matching block. This code runs the right calculation.

double result = 0;
switch (choice) {
case 1:
result = a + b;
System.out.println("Result: " + result);
break;
case 2:
result = a - b;
System.out.println("Result: " + result);
break;
case 3:
result = a * b;
System.out.println("Result: " + result);
break;
case 4:
result = a / b;
System.out.println("Result: " + result);
break;
default:
System.out.println("That is not a valid option.");
}

Walking through it:

  • switch (choice) jumps to the matching case.
  • case 1 adds, case 2 subtracts, case 3 multiplies, case 4 divides. Each stores the answer in result and prints it.
  • The break at the end of each case stops the switch there. Without it, Java falls through and runs the next case too.
  • The default block runs when no case matches, like typing 9. It prints a friendly message instead of doing nothing.

One problem hides in case 4. If the second number is zero, a / b divides by zero. Let’s fix that next.

🛡️ Step 4: handle divide-by-zero gracefully

Dividing by zero is the classic calculator bug. The fix is the same in both cases: check for zero before dividing.

  • Whole-number division by zero throws an ArithmeticException and crashes.
  • double division does not crash but prints a strange value like Infinity or NaN.

This version guards the divide case so a zero divisor never reaches the division.

case 4:
if (b == 0) {
System.out.println("Cannot divide by zero. Try again.");
} else {
result = a / b;
System.out.println("Result: " + result);
}
break;

Why this works:

  • if (b == 0) checks the second number before any division.
  • If it is zero, we print a clear message and skip the math. The program stays alive.
  • If it is not zero, the else block divides safely and prints the result.

Guarding a risky operation before you run it is the difference between a crash and a program that keeps going. Now let’s make the whole thing repeat.

🔁 Step 5: loop until the user exits

Right now the calculator does one sum and stops. We wrap the menu, input, and switch in a while loop controlled by a boolean flag. When the user picks Exit, we flip the flag and the loop ends. This is the loop structure.

boolean running = true;
while (running) {
System.out.println("\n--- Simple Calculator ---");
System.out.println("1. Add (+)");
System.out.println("2. Subtract (-)");
System.out.println("3. Multiply (x)");
System.out.println("4. Divide (/)");
System.out.println("5. Exit");
System.out.print("Choose an option: ");
int choice = scanner.nextInt();
if (choice == 5) {
running = false;
System.out.println("Goodbye!");
continue;
}
// read numbers and run the switch here
}

Reading the loop:

  • boolean running = true; is a flag that says “keep going”. The loop runs while it stays true.
  • while (running) checks the flag at the top of every round.
  • Each round prints the menu fresh. The \n adds a blank line so rounds do not blur together.
  • Picking 5 sets running = false, says goodbye, and continues. The flag is now false, so the loop ends.
  • Any other choice falls through to reading the numbers and running the switch.

Before we assemble the full version, let’s give each operation its own method.

🧩 Step 6: a method per operation (optional but clean)

Inline math in the switch works fine. But one small method per operation reads better and is reusable. Each does one job with a clear name. These four methods replace the inline math.

static double add(double a, double b) {
return a + b;
}
static double subtract(double a, double b) {
return a - b;
}
static double multiply(double a, double b) {
return a * b;
}
static double divide(double a, double b) {
return a / b; // caller checks for zero first
}

A few notes:

  • Each method is static so main can call it without creating an object.
  • Each takes two double values and returns a double. The name makes the call read like English: add(a, b).
  • divide does not check for zero itself. We keep that guard in the caller. Both are valid; here we keep methods simple and guard at the call.

Now let’s put everything together.

📦 Step 7: the full program

Here is the complete calculator. It loops the menu, reads a choice and two numbers, runs the right method, guards divide-by-zero, handles bad choices, and exits cleanly.

import java.util.Scanner;
public class Calculator {
static double add(double a, double b) {
return a + b;
}
static double subtract(double a, double b) {
return a - b;
}
static double multiply(double a, double b) {
return a * b;
}
static double divide(double a, double b) {
return a / b;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean running = true;
while (running) {
System.out.println("\n--- Simple Calculator ---");
System.out.println("1. Add (+)");
System.out.println("2. Subtract (-)");
System.out.println("3. Multiply (x)");
System.out.println("4. Divide (/)");
System.out.println("5. Exit");
System.out.print("Choose an option: ");
int choice = scanner.nextInt();
if (choice == 5) {
running = false;
System.out.println("Goodbye!");
continue;
}
if (choice < 1 || choice > 4) {
System.out.println("That is not a valid option. Try again.");
continue;
}
System.out.print("Enter first number: ");
double a = scanner.nextDouble();
System.out.print("Enter second number: ");
double b = scanner.nextDouble();
switch (choice) {
case 1:
System.out.println("Result: " + add(a, b));
break;
case 2:
System.out.println("Result: " + subtract(a, b));
break;
case 3:
System.out.println("Result: " + multiply(a, b));
break;
case 4:
if (b == 0) {
System.out.println("Cannot divide by zero. Try again.");
} else {
System.out.println("Result: " + divide(a, b));
}
break;
}
}
scanner.close();
}
}

How it flows:

  • The loop keeps the program alive. Each round prints the menu and reads a choice. Exit ends the loop.
  • A choice outside 1 to 4 is rejected before we ask for numbers.
  • Valid choices read two numbers and run the matching method. Divide checks for zero first.
  • Guard order matters: Exit first, then invalid option, then ask for numbers. Cheap checks early means we never read numbers for a choice we will reject.

▶️ Step 8: a sample run

Let’s run it and see the whole thing work: an add, a divide, a divide-by-zero, a bad option, and exit.

Output

--- Simple Calculator ---
1. Add (+)
2. Subtract (-)
3. Multiply (x)
4. Divide (/)
5. Exit
Choose an option: 1
Enter first number: 12
Enter second number: 8
Result: 20.0
--- Simple Calculator ---
Choose an option: 4
Enter first number: 9
Enter second number: 2
Result: 4.5
--- Simple Calculator ---
Choose an option: 4
Enter first number: 7
Enter second number: 0
Cannot divide by zero. Try again.
--- Simple Calculator ---
Choose an option: 9
That is not a valid option. Try again.
--- Simple Calculator ---
Choose an option: 5
Goodbye!

Each menu choice runs its own path. The divide-by-zero attempt shows a calm message instead of a crash. The invalid option 9 is rejected without asking for numbers. And 5 exits cleanly.

🛠️ Practice Challenge

Try extending the calculator before checking the answers. Each one builds on the program you just wrote.

Challenge 1: Add a modulus operation (the remainder of a division, using %) as menu option 6.

Challenge 2: Add a power operation that raises the first number to the second (for example 2 to the power 3 is 8).

Challenge 3: Stop the program crashing when the user types text like “abc” instead of a number.

⚠️ Common Mistakes

A few calculator slip-ups to watch for.

  • Forgetting break in the switch. Without break, one case runs into the next (“fall through”) and you get the wrong result. Every case needs its own break.
  • Not guarding divide-by-zero. Whole-number division by zero crashes; decimal division prints Infinity or NaN. Always check the divisor before dividing.
  • Reading with nextInt() for decimals. If users may type 3.5, read with nextDouble(). nextInt() crashes on a decimal point.
  • No exit option. A calculator that never stops, or one that quits after a single sum, both frustrate users. Give a clear Exit and loop until they choose it.
  • Ignoring bad menu choices. A choice like 9 should get a friendly message from a default or a range check, not silent nothing.

✅ Best Practices

Habits that make a console calculator clean and reliable.

  • Loop with a clear flag. A boolean running controlled by the Exit option makes the program’s lifetime obvious at a glance.
  • One method per operation. add, subtract, multiply, and divide each do one job, so the switch stays short and the code reads like English.
  • Guard risky operations early. Check for divide-by-zero and invalid options before doing the work, so nothing crashes.
  • Use double for flexible math. It handles whole numbers and decimals, so the calculator works for 2 + 2 and 2.5 + 1.1 alike.
  • Validate input. Reject out-of-range choices and re-ask on non-number input so a typo never ends the program.

🧩 What You’ve Learned

Nicely done. You built a complete, runnable console calculator from scratch. Let’s recap.

  • ✅ A menu loop with a boolean running flag keeps the calculator alive until the user exits.
  • ✅ A Scanner reads the menu choice and two numbers, using nextDouble() so decimals work.
  • ✅ A switch on the choice picks the right operation, with a break in every case.
  • ✅ A divide-by-zero guard checks the divisor first, so the program never crashes.
  • A method per operation (add, subtract, multiply, divide) keeps main short and clear.
  • Input validation rejects bad menu choices and, with hasNextDouble(), survives non-number typing.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    Why does each case in the switch need a break?

    Why: Without break, control falls through and runs the next case too, giving a wrong result.

  2. 2

    What is the safe way to handle dividing by zero?

    Why: Checking the divisor before the division prevents the crash and lets you show a clear message.

  3. 3

    Why read the numbers with nextDouble() instead of nextInt()?

    Why: nextDouble() reads decimals, so the calculator works for whole numbers and fractions alike.

  4. 4

    What keeps the calculator running until the user exits?

    Why: A while loop checks the running flag each round; picking Exit sets it false and ends the loop.

🚀 What’s Next?

You have the core skills now: input, decisions, loops, and safe guards. Next we level up to a project with real data and CRUD operations, a Student Management System that stores many records and lets you add, view, update, and remove them. Let’s build it.

Java Student Management System

Share & Connect