I finished my first calculator using Java!
I try to apply Object-Oriented Programming!
I'll add my gitHub link if you're suited to viewing code on gitHub.
Here is a link to my GitHub Calculator Project
I enabled the calculator to calculate data type of Double, so it can get result containing decimals.
When reviewing, can you focus on whether my code
- follows clean code
- classes are divided reasonably
- handled exceptions well (such when doing calculation)
- has no redundant or repeated codes
Main Class
enter code hereimport java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// take in option chose in the menu & instantiate all the objects
Menu menu = new Menu();
Calculator calculate = new Calculator();
Database database = new Database();
EquationConverter equationConverter = new EquationConverter();
EquationFormatChecker equationFormatChecker = new EquationFormatChecker();
// Starting Calculator
System.out.println("Calculator Initializing...");
// Main Loop of Options
while(true) {
// Checking Input if it's 1 or 2 or 3
while(true) {
System.out.println("-------------------");
System.out.println("1. History\n2. Calculation\n3. Terminate");
try {
menu.setMenuChoice(Integer.parseInt(br.readLine()));
if (menu.getMenuChoice() >= 1 && menu.getMenuChoice() <= 3) {
break;
}
} catch (NumberFormatException e) {
System.out.println(">>> Wrong Input, please try again.");
}
}
// using if else to figure out whether to view history/perform calculation/exit program
switch (menu.getMenuChoice()) {
// view history
case 1 -> {
if (database.checkEmpty()) {
System.out.println("Retrieving History...\n");
System.out.println(database.getHistory());
} else {
System.out.println(">>> History's Empty");
}
}
// do calculation
case 2 -> {
boolean continueCalculation = true;
while (continueCalculation) {
try {
System.out.println("-------------------");
System.out.print("Enter equation (Example: 1 + 4 * 5 / 2)\n=> ");
// take in the equation as String and pass it on to equation convertor
String equation = br.readLine();
equationConverter.setEverything(equation);
// checking validity of equation
boolean validityCheck = equationFormatChecker.checkValidity(equationConverter.getNumbersList(), equationConverter.getOperatorsList());
if (validityCheck) {
// code is in this order because of possible ArithmeticException in calculate
// find the answer
Double answer = calculate.calculateEquation(equationConverter.getNumbersList(), equationConverter.getOperatorsList());
// add equation to history (only equation, not answer)
database.addHistory(equation);
System.out.println("Answer: " + answer);
//and add answer to the database
database.addAnswerToEquation(answer);
continueCalculation = false;
}
} catch (NumberFormatException e1) {
System.out.println("Wrong format, try again.");
} catch (ArithmeticException e2) {
if (e2.getMessage().equals("Infinite"))
System.out.println("Can't divide by zero. Try again.");
if (e2.getMessage().equals("NaN")) System.out.println("Not a Number. Try Again");
}
}
}
// exit program
case 3 -> {
System.out.println("Terminating calculator...");
System.exit(0);
}
}
}
}
}
Menu Class
public class Menu {
private int menuChoice;
public void setMenuChoice(int menuChoice) {
this.menuChoice = menuChoice;
}
public int getMenuChoice() {
return menuChoice;
}
}
EquationConverter Class
import java.util.ArrayList;
import java.util.List;
public class EquationConverter {
private ArrayList<String> equationList;
private ArrayList<Double> numbersList;
private ArrayList<String> operatorsList;
// initialize equationList
EquationConverter() {
equationList = new ArrayList<>();
numbersList = new ArrayList<>();
operatorsList = new ArrayList<>();
}
// set the Equation
public void setEverything(String equationString) {
equationList.clear();
equationList.addAll(List.of(equationString.split(" ")));
setNumbersList();
setOperatorsList();
}
// get equationList
public ArrayList<String> getEquationList() {
return equationList;
}
// set list of numbers
public void setNumbersList() {
numbersList = new ArrayList<>();
for (int i = 0; i < equationList.size(); i += 2) {
numbersList.add(Double.parseDouble(equationList.get(i)));
}
}
// set list of operators
public void setOperatorsList() {
operatorsList = new ArrayList<>();
for (int i = 1; i < equationList.size(); i += 2) {
operatorsList.add(equationList.get(i));
}
}
public ArrayList<Double> getNumbersList() {
return numbersList;
}
public ArrayList<String> getOperatorsList() {
return operatorsList;
}
}
EquationFormatChecker Class
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class EquationFormatChecker {
private final List<String> operatorSet = new ArrayList<>(Arrays.asList("+", "-", "*", "/"));
// 0 for valid equation, 1 for invalid equation, 2 for division by zero
public boolean checkValidity(ArrayList<Double> numbers, ArrayList<String> operators) {
int length = numbers.size() + operators.size();
// checking if either List is empty or length is valid
if (numbers.isEmpty() || operators.isEmpty() || length < 3 || length % 2 == 0) {
return false;
}
// check if operatorsList contains + - * /
for (String operator : operators) {
if (!operatorSet.contains(operator)) {
return false;
}
}
return true;
}
}
Calculator Class
import java.util.ArrayList;
public class Calculator {
private ArrayList<Double> numberList;
private ArrayList<String> operatorList;
public double calculateEquation(ArrayList<Double> numbersList, ArrayList<String> operatorList) throws ArithmeticException {
this.numberList = numbersList;
this.operatorList = operatorList;
for (int i = 0; i < operatorList.size(); i++) {
if (operatorList.get(i).equals("*")) {
numbersList.set(i + 1, numbersList.get(i) * numbersList.get(i + 1));
operatorList.set(i, "+");
numbersList.set(i, 0D);
}
if (operatorList.get(i).equals("/")) {
double result = numbersList.get(i) / numbersList.get(i + 1);
if (Double.isInfinite(result)) throw new ArithmeticException("Infinite");
if (Double.isNaN(result)) throw new ArithmeticException("NaN");
numbersList.set(i + 1, numbersList.get(i) / numbersList.get(i + 1));
operatorList.set(i, "+");
numbersList.set(i, 0D);
}
}
Double accumulator = numbersList.get(0);
for (int i = 1; i < numberList.size(); i++) {
if (operatorList.get(i - 1).equals("+")) {
accumulator += numbersList.get(i);
}
if (operatorList.get(i - 1).equals("-")) {
accumulator -= numbersList.get(i);
}
}
return accumulator;
}
public ArrayList<Double> getNumberList() {
return numberList;
}
public ArrayList<String> getOperatorList() {
return operatorList;
}
}
Database Class
import javax.xml.crypto.Data;
import java.util.ArrayList;
public class Database {
private ArrayList<String> historyList;
private String historyString;
Database() {
this.historyList = new ArrayList<>();
}
public boolean checkEmpty() {
if (historyList.isEmpty()) {
return false;
} return true;
}
// add a line of equation to the String
public void addHistory(String equation) {
this.historyList.add(equation);
}
// return historyString
public String getHistory() {
ArrayListToString();
return historyString;
}
// convert historyList to String
private void ArrayListToString() {
StringBuilder sb = new StringBuilder();
for (String oneEquation : historyList) {
sb.append(oneEquation.concat("\n"));
}
historyString = sb.toString();
}
// add answer to complete your equation
public void addAnswerToEquation(Double answer) {
String stringAnswer = String.valueOf(answer);
historyList.set(historyList.size() - 1, historyList.get(historyList.size() - 1).concat(" = " + stringAnswer));
}
public ArrayList<String> getHistoryList() {
return historyList;
}
public String getHistoryString() {
return historyString;
}
}