I have a simple calculator program that needs some reviewing. Is this as efficient as it can get, or is there a better way?
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(Exception 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("n") || s.equalsIgnoreCase("f") || s.equalsIgnoreCase("false"))
return false;
}
}
public static Double calculate(String s) throws IllegalArgumentException {
IllegalArgumentException exception = new IllegalArgumentException("Illegal Calculation.");
String a = "";
ArrayList<Double> o = new ArrayList<Double>(s.length());
ArrayList<String> z = new ArrayList<String>(s.length());
double j = 0.0;
double k = 0.0;
int iInARow = 0;
int sInARow = 0;
boolean hasDecimal = false;
boolean out = false;
for(int i = 0 ; i < s.length() ; i++) {
if(out)
break;
k = j;
try {
j = Integer.parseInt(s.charAt(i) + "");
iInARow++;
sInARow = 0;
String d = hasDecimal == true ? "." : "";
hasDecimal = false;
if(iInARow >= 2) {
Double dou = k;
Character character = dou.toString().charAt(dou.toString().lastIndexOf(".") + 1);
if(!character.equals('0'))
j = Double.parseDouble(k + d + (int) j);
else
j = Double.parseDouble((int) k + d + (int) j);
}
d = "";
try {
Integer.parseInt(s.charAt(i + 1) + "");
} catch(Exception e) {
Character c;
try {
c = s.charAt(i + 1);
} catch(StringIndexOutOfBoundsException exc) {
c = 'a';
}
if(!c.equals('.'))
o.add(j);
}
} catch(Exception e) {
Character c = s.charAt(i);
if(c.equals('.')) {
hasDecimal = true;
continue;
} else if(c.equals('!')) {
o.add(0.0);
} else if(c.toString().equals(" ")) {
continue;
} else {
sInARow++;
iInARow = 0;
}
if(sInARow == 2) {
throw exception;
} else {
a = c.toString();
}
z.add(a);
if(a.equals("!")) {
try {
s.charAt(i + 1);
} catch(StringIndexOutOfBoundsException exc) {
out = true;
}
}
}
}
o.trimToSize();
z.trimToSize();
for(int i = 0 ; i <= o.size() ; i++) {
if(z.contains("^")) {
if(o.get(z.indexOf("^") + 1).toString().contains(".") && !o.get(z.indexOf("^")).toString().matches("[0-9]+\\.0"))
throw exception;
o.set(z.lastIndexOf("^"), power(o.get(z.lastIndexOf("^")), (int) ((o.get(z.lastIndexOf("^") + 1)) + 0)));
o.remove(z.lastIndexOf("^") + 1);
z.remove("^");
} else if(z.contains("!")) {
if(o.get(z.indexOf("!")).toString().contains(".") && !o.get(z.indexOf("!")).toString().matches("[0-9]+\\.0"))
throw exception;
o.set(z.indexOf("!"), (double) factorial((int) (o.get(z.indexOf("!")) + 0)));
o.remove(z.indexOf("!") + 1);
z.remove("!");
} else if(z.contains("/")) {
BigDecimal bd = new BigDecimal(o.get(z.indexOf("/")).toString());
BigDecimal bd2 = new BigDecimal(o.get(z.indexOf("/") + 1).toString());
bd = bd.divide(bd2);
o.set(z.indexOf("/"), o.get(z.indexOf("/")) / o.get(z.indexOf("/") + 1));
o.remove(z.indexOf("/") + 1);
z.remove("/");
} else if(z.contains("*")) {
BigDecimal bd = new BigDecimal(o.get(z.indexOf("*")).toString());
BigDecimal bd2 = new BigDecimal(o.get(z.indexOf("*") + 1).toString());
bd = bd.multiply(bd2);
bd.setScale(bd.scale() + bd2.scale());
o.set(z.indexOf("*"), bd.doubleValue());
o.remove(z.indexOf("*") + 1);
z.remove("*");
} else if(z.contains("-")) {
o.set(z.indexOf("-"), o.get(z.indexOf("-")) - o.get(z.indexOf("-") + 1));
o.remove(z.indexOf("-") + 1);
z.remove("-");
} else if(z.contains("+")) {
o.set(z.indexOf("+"), o.get(z.indexOf("+")) + o.get(z.indexOf("+") + 1));
o.remove(z.indexOf("+") + 1);
z.remove("+");
} else {
if(!z.isEmpty())
throw exception;
}
}
return o.get(0);
}
public static int factorial(int i) {
if(i == 1)
return 1;
else
return i * factorial(i - 1);
}
public static double power(double i, int j) {
if(j == 1) {
return i;
} else if(j == 0) {
return 1;
} else {
return i * power(i , j - 1);
}
}
The class name and the import statements do not matter.
Sample output:
Welcome to the Calculator! Type a calculation: 2 + 2 <--- Input The answer is: 4.0 Again? yes <--- Input Type a calculation: 2 - 2 <--- Input The answer is: 0.0 Again? y <--- Input Type a calculation: 2 * 2 <--- Input The answer is: 4.0 Again? true <--- Input Type a calculation: 2 / 2 <--- Input The answer is: 1.0 Again? yep <--- Input Again? yes <--- Input Type a calculation: 2! <--- Input The answer is: 2.0 Again? t <--- Input Type a calculation: 2 ^ 2 <--- Input The answer is: 4.0 Again? no <--- Input