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 + 35Result: 53.0

These are the steps the program takes:

- Line 5 sets up a Scanner.
- 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. - Line 8 prompts the user to enter an expression.
- 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`next`

methods (except*X*`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`

. - 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`

. - Likewise, line 11 immediately reads the third token (35). This goes in
`operand2`

. - On line 13 is the start of an
*if*statement. It simply checks if`operator`

contains a +.- If true, line 14 simply adds
`operand1`

and`operand2`

together and prints the result (53.00).

- If false, the program ends without doing anything.

- If true, line 14 simply adds

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.74Result: 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.2Result: 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.842Result: 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.2Result: 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 / 34Result: 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:

Input | Pattern | Output | Explanation |
---|---|---|---|

0.1283796 | 0.### | 0.128 | Integer: 1 digit minimum.Fraction: 3 digits optional. |

5 | 0.### | 5 | Integer: 1 digit minimum.Fraction: 3 digits optional. |

7.369711 | 0.### | 7.37 | Integer: 1 digit minimum.Fraction: 3 digits optional. |

0.915 | 0.00 | 0.92 | Integer: 1 digit minimum.Fraction: 2 digits exactly. |

3.915 | #.00 | 3.92 | Integer: 1 digit optional.Fraction: 2 digits exactly. |

0.915 | #.00 | .92 | Integer: 1 digit optional (shows nothing if 0).Fraction: 2 digits exactly. |

522.915 | 0.000000## | 522.915000 | Integer: 1 digit minimum.Fraction: 6 digits minimum and 2 optional. |

522.91584176 | 0.0000## | 522.915842 | Integer: 1 digit minimum.Fraction: 4 digits minimum and 2 optional. |

8.915 | 00000.00000 | 00008.91500 | Integer: 5 digits minimum.Fraction: 5 digits exactly. |

0.9756962 | 0.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.00 | Integer: 1 digit minimum. Add comma every third digit.Fraction: 2 digits minimum and 3 optional. |

612447.817 | €0.00### | €612447.817 | Integer: 1 digit minimum. Add symbol (€) to the front.Fraction: 2 digits minimum and 3 optional. |

58377429.147 | £,##0.00 | £58,377,429.15 | Integer: 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. |