This is my revised code of the Calculator
:
import java.math.*;
import java.util.*;
public class Calculator {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Welcome to the Calculator!");
do {
System.out.println("\nType a calculation:");
String s = sc.nextLine();
try {
System.out.println("\nThe answer is: " + calculate(s));
} catch (IllegalArgumentException e) {
System.out.println("Oops! Illegal calculation.");
}
} while (doAgain(sc));
System.out.println("\nThank you for using the calculator!");
sc.close();
}
private static boolean doAgain(Scanner sc) {
while (true) {
System.out.println("\nAgain?");
String s = sc.nextLine();
if (s.equalsIgnoreCase("y") || s.equalsIgnoreCase("yes")
|| s.equalsIgnoreCase("t") || s.equalsIgnoreCase("true"))
return true;
else if (s.equalsIgnoreCase("n") || s.equalsIgnoreCase("no")
|| s.equalsIgnoreCase("f") || s.equalsIgnoreCase("false"))
return false;
}
}
public static Double calculate(String s) throws IllegalArgumentException {
IllegalArgumentException exception = new IllegalArgumentException(
"Illegal Calculation.");
ArrayList<Double> nums = new ArrayList<Double>(s.length());
ArrayList<String> op = new ArrayList<String>(s.length());
getNumsAndOp(nums, op, s, exception);
for (int i = 0; i <= nums.size(); i++) {
if (op.contains("^")) {
if (nums.get(op.indexOf("^") + 1).toString().contains(".")
&& !nums.get(op.indexOf("^")).toString()
.matches("[0-9]+\\.0"))
throw exception;
nums.set(op.lastIndexOf("^"), Expressions.power(
nums.get(op.lastIndexOf("^")),
(int) ((nums.get(op.lastIndexOf("^") + 1)) + 0)));
nums.remove(op.lastIndexOf("^") + 1);
op.remove("^");
} else if (op.contains("!")) {
if (nums.get(op.indexOf("!")).toString().contains(".")
&& !nums.get(op.indexOf("!")).toString()
.matches("[0-9]+\\.0"))
throw exception;
nums.set(op.indexOf("!"), (double) Expressions
.factorial((int) (nums.get(op.indexOf("!")) + 0)));
nums.remove(op.indexOf("!") + 1);
op.remove("!");
} else if (op.contains("/")) {
multiplyOrDivide(nums, op, "/");
} else if (op.contains("*")) {
multiplyOrDivide(nums, op, "*");
} else if (op.contains("-")) {
plusOrMinus(nums, op, "-");
} else if (op.contains("+")) {
plusOrMinus(nums, op, "+");
} else if (!op.isEmpty()) {
throw exception;
}
}
return nums.get(0);
}
private static void plusOrMinus(ArrayList<Double> nums,
ArrayList<String> op, String plusOrMinus) {
int index = op.indexOf(plusOrMinus);
if (plusOrMinus.equals("+")) {
nums.set(index, nums.get(index) + nums.get(index + 1));
} else {
nums.set(index, nums.get(index) - nums.get(index + 1));
}
nums.remove(index + 1);
op.remove(index);
}
private static void multiplyOrDivide(ArrayList<Double> nums,
ArrayList<String> op, String multiplyOrDivide) {
int index = op.indexOf(multiplyOrDivide);
BigDecimal bd = new BigDecimal(nums.get(index).toString());
BigDecimal bd2 = new BigDecimal(nums.get(index + 1).toString());
if (multiplyOrDivide.equals("*")) {
bd = bd.multiply(bd2);
bd.setScale(bd.scale() + bd2.scale());
} else {
bd = bd.divide(bd2);
}
nums.set(index, bd.doubleValue());
nums.remove(index + 1);
op.remove(index);
}
private static void getNumsAndOp(ArrayList<Double> nums,
ArrayList<String> op, String s, IllegalArgumentException exception)
throws IllegalArgumentException {
String toAdd = "";
double num = 0.0;
double previousNum = 0.0;
int iInARow = 0;
int sInARow = 0;
boolean hasDecimal = false;
for (int i = 0; i < s.length(); i++) {
previousNum = num;
try {
num = Integer.parseInt(s.charAt(i) + "");
iInARow++;
sInARow = 0;
String dec = hasDecimal ? "." : "";
hasDecimal = false;
if (iInARow >= 2) {
Double dou = previousNum;
if (previousNum - dou.longValue() == 0)
num = Double.parseDouble((int) previousNum + dec
+ (int) num);
else
num = Double.parseDouble(previousNum + dec + (int) num);
}
dec = "";
try {
Integer.parseInt(Character.toString(s.charAt(i + 1)));
} catch (Exception e) {
Character c;
try {
c = s.charAt(i + 1);
} catch (StringIndexOutOfBoundsException exc) {
c = 'a';
}
if (!c.equals('.'))
nums.add(num);
}
} catch (Exception e) {
Character c = s.charAt(i);
if (c.equals('.')) {
hasDecimal = true;
continue;
} else if (c.equals('!')) {
nums.add(0.0);
} else if (c.toString().equals(" ")) {
continue;
} else {
sInARow++;
iInARow = 0;
}
if (sInARow == 2) {
throw exception;
} else {
toAdd = c.toString();
}
op.add(toAdd);
if (toAdd.equals("!")) {
try {
s.charAt(i + 1);
} catch (StringIndexOutOfBoundsException exc) {
break;
}
}
}
}
nums.trimToSize();
op.trimToSize();
}
}
System.err.println
function that should be leveraged in place ofSystem.out.println
for theIllegalArgumentException
. Of course, an external logging library would be better still. \$\endgroup\$