We will now write a simple calculator program that can perform the four basic operations: add, subtract, multiply, and divide. The program will prompt user to input a simple expression such as 3 + 7 and the program will output the result. Here is the first version of the program that is capable of adding numbers together.

import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("Simple Calculator - Enter a simple expression consisting of\ntwo numbers and one operator, separated by spaces (e.g. 7 + 2).");
        System.out.print("Expression: ");
        double operand1 = sc.nextDouble();
        String operator = sc.next();
        double operand2 = sc.nextDouble();

        if (operator.equals("+")) {
            System.out.println("Result: " + (operand1 + operand2));
        }
    }
}
[Run]
Simple Calculator - Enter a simple expression consisting of
two numbers and one operator, separated by spaces (e.g. 7 + 2).
Expression: 18 + 35
Result: 53.0

These are the steps the program takes:

  1. Line 5 sets up a Scanner.
  2. Line 7 prints an instructional message. The string contains a \n which is why the message is split into two lines in the sample run.
  3. Line 8 prompts the user to enter an expression.
  4. Line 9 blocks for input. In the console, the expression 18 + 35 is entered. From the Scanner’s point of view, we have just entered three tokens (because the Scanner likes to separate things by spaces). The first token is 18, the second is +, and the third is 35. Remember that the Scanner’s various nextX methods (except nextLine) only attempt to read one token. Therefore, the nextDouble on line 9 only reads the first token (18). It is then stored in variable operand1.
  5. On line 10, because there’s still two tokens left, the next method immediately reads the second token (+), and therefore doesn’t need to block for input. The + is stored in variable operator as a String.
  6. Likewise, line 11 immediately reads the third token (35). This goes in operand2.
  7. On line 13 is the start of an if statement. It simply checks if operator contains a +.
    1. If true, line 14 simply adds operand1 and operand2 together and prints the result (53.00).
    1. If false, the program ends without doing anything.

This approach means spaces are necessary otherwise the Scanner will read too much at once and the program won’t function correctly or, more likely, will crash. For example, inputting 7+ 3 won’t work because 7+ is a single token and cannot be interpreted as a double on line 9, resulting in an exception (error). Now let’s add the other three operations.

import java.util.Scanner;

public class Calculator {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("Simple Calculator - Enter a simple expression consisting of\ntwo numbers and one operator, separated by spaces (e.g. 7 + 2).");
        System.out.print("Expression: ");
        double operand1 = sc.nextDouble();
        String operator = sc.next();
        double operand2 = sc.nextDouble();

        if (operator.equals("+")) {
            System.out.println("Result: " + (operand1 + operand2));
        }
        else if (operator.equals("-")) {
            System.out.println("Result: " + (operand1 - operand2));
        }
        else if (operator.equals("*")) {
            System.out.println("Result: " + (operand1 * operand2));
        }
        else if (operator.equals("/")) {
            System.out.println("Result: " + (operand1 / operand2));
        }
        else {
            System.out.println("Invalid operation.");
        }
    }
}

Lines 16-27 are new. Lines 16-24 consist of three else if blocks that do the same thing as the first if block, except they check for a different symbol and perform a different operation. The else block on lines 25-27 will run if none of the others blocks match and will print “Invalid operation.”

[Run]
Simple Calculator - Enter a simple expression consisting of
two numbers and one operator, separated by spaces (e.g. 7 + 2).
Expression: 6.8 * 7.74
Result: 52.632

There is a small problem. We’re using double, which is a floating-point type, so this can happen:

[Run]
Simple Calculator - Enter a simple expression consisting of
two numbers and one operator, separated by spaces (e.g. 7 + 2).
Expression: 0.3 – 0.2
Result: 0.09999999999999998

That result is an atom away from 0.1 but it’s not good enough visually. We could use printf to round the result before printing, and use the format specifier %.7f so we always get 7 digits after the decimal point. But then the result of 0.3 – 0.2 would be formatted as 0.1000000, which, while technically correct, still looks unprofessional.

DecimalFormat

A better alternative is to use the built-in class DecimalFormat. This class is used to format decimal numbers. Like the Scanner, we need to create an object/instance of the DecimalFormat class and use that. We also supply it a pattern that specifies how it should format decimal numbers. We can then pass any results into the format method to obtain the formatted equivalent. Here is the updated code:

import java.text.DecimalFormat;
import java.util.Scanner;

public class Calculator2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("Simple Calculator - Enter a simple expression consisting of\ntwo numbers and one operator, separated by spaces (e.g. 7 + 2).");
        System.out.print("Expression: ");
        double operand1 = sc.nextDouble();
        String operator = sc.next();
        double operand2 = sc.nextDouble();

        DecimalFormat df = new DecimalFormat("0.#########");

        if (operator.equals("+")) {
            System.out.println("Result: " + df.format(operand1 + operand2));
        } 
        else if (operator.equals("-")) {
            System.out.println("Result: " + df.format(operand1 - operand2));
        } 
        else if (operator.equals("*")) {
            System.out.println("Result: " + df.format(operand1 * operand2));
        } 
        else if (operator.equals("/")) {
            System.out.println("Result: " + df.format(operand1 / operand2));
        } 
        else {
            System.out.println("Invalid operation.");
        }
    }
}

Line 1 imports the DecimalFormat class, which is necessary to use it. Line 14 declares a variable called df (short for DecimalFormat). Its type is DecimalFormat meaning df can reference (hold) a DecimalFormat object. The right side is what actually creates a DecimalFormat object using the new keyword. Between the parentheses is the string “0.#########”. This string is the pattern that the DecimalFormat will follow when formatting a decimal number. As we can see, the pattern consists of 9 pound/hash (#) signs to the right of the decimal point (the fractional part) and 1 zero to the left of the decimal point (the integral/integer part). Hashes represent an optional digit, meaning that if we give DecimalFormat a number, it will give back the number with the fractional part rounded up to 9 digits. A zero represents a required digit. The integer part is always wholly given regardless of the pattern, but the zero ensures at least one digit will appear where DecimalFormat may omit it otherwise.

Let’s look at line 4 where df is used. Line 4 still calculates operand1 + operand2 like normal but it’s placed within the format method. This means the result of operand1 + operand2 goes into the method, which, in turn, formats it and then returns the formatted result. Then the print statement simply prints it. Lines 20, 23, and 26 do the exact same thing but for the other three operators (subtraction, multiplication, division). To make sure it works, let’s go through some test runs:

[Run 1]
Simple Calculator - Enter a simple expression consisting of
two numbers and one operator, separated by spaces (e.g. 7 + 2).
Expression: 511.295 + 1374.842
Result: 1886.137
[Run 2]
Simple Calculator - Enter a simple expression consisting of
two numbers and one operator, separated by spaces (e.g. 7 + 2).
Expression: 0.3 – 0.2
Result: 0.1
[Run 3]
Simple Calculator - Enter a simple expression consisting of
two numbers and one operator, separated by spaces (e.g. 7 + 2).
Expression: 100 / 34
Result: 2.941176471

All three runs give correct and properly formatted results. Remember that the hashes in the pattern represent optional digits so a formatted number will have anywhere between 0 and 9 digits (after the decimal point). So, Run 1 gives us 1886.137. Run 2 gives us 0.1 this time due to rounding, instead of 0.09999999999999998. Run 3 results in a recurring number but it is rounded to 9 decimal places as the patterns specifies no more than 9 digits. DecimalFormat can be used to achieve various formats. Here are some more examples of patterns and their effect on input:

InputPatternOutputExplanation
0.12837960.###0.128Integer: 1 digit minimum.
Fraction: 3 digits optional.
50.###5Integer: 1 digit minimum.
Fraction: 3 digits optional.
7.3697110.###7.37Integer: 1 digit minimum.
Fraction: 3 digits optional.
0.9150.000.92Integer: 1 digit minimum.
Fraction: 2 digits exactly.
3.915#.003.92Integer: 1 digit optional.
Fraction: 2 digits exactly.
0.915#.00.92Integer: 1 digit optional (shows nothing if 0).
Fraction: 2 digits exactly.
522.9150.000000##522.915000Integer: 1 digit minimum.
Fraction: 6 digits minimum and 2 optional.
522.915841760.0000##522.915842Integer: 1 digit minimum.
Fraction: 4 digits minimum and 2 optional.
8.91500000.0000000008.91500Integer: 5 digits minimum.
Fraction: 5 digits exactly.
0.97569620.0#%97.57%Integer: 1 digit minimum.
Fraction: 1 digit minimum and 1 optional.
Input is expected to be normalised (between 0 and 1)
because it gets multiplied by 100.
1000000,##0.00###1,000,000.00Integer: 1 digit minimum. Add comma every third digit.
Fraction: 2 digits minimum and 3 optional.
612447.817€0.00###€612447.817Integer: 1 digit minimum. Add symbol (€) to the front.
Fraction: 2 digits minimum and 3 optional.
58377429.147£,##0.00£58,377,429.15Integer: 1 digit minimum.
Add comma every third digit.
Add symbol (£) to the front.
Fraction: 2 digits exactly.
0.10#.##0.1 (not .1)Works but is somewhat misleading.
Typically, a leading or trailing 0 will be omitted where there’s a #.
I think Java reinterprets the pattern as 0.## behind the scenes.
DecimalFormat patterns

Leave a Reply

Your email address will not be published. Required fields are marked *