在Java里动手做一个简单计算器,是理解基础语法最好的练手方式。它不需要图形界面,仅靠控制台输入就能覆盖算术运算符、关系判断以及多种分支结构的用法。下面我们先看一个最直观的运行效果示意图,再逐步拆开每一层逻辑。

一、输入接收与数据类型选择
计算器的第一步是拿到用户输入的两个操作数以及运算符。在控制台程序中,我们通常使用Scanner来读取内容。操作数推荐用double类型而不是int,因为用户可能输入小数,而且除法结果也经常带有小数部分。如果强行用整数类型,会遇到精度丢失和除不尽被截断的问题。
运算符一般按字符串读取,取第一个字符就能参与判断。这里要注意,nextDouble之后如果直接调用next读符号,缓冲区里的换行符可能导致读取异常,稳妥的做法是用nextLine配合charAt(0),或者统一用next读取字符串再解析。下面这段代码展示了基础的输入框架。
import java.util.Scanner;
public class CalcDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入第一个数字: ");
double a = sc.nextDouble();
System.out.print("请输入运算符(+ - * /): ");
String opStr = sc.next();
char op = opStr.charAt(0);
System.out.print("请输入第二个数字: ");
double b = sc.nextDouble();
// 后续分支处理
sc.close();
}
}
从工程角度看,把输入和运算拆成不同方法会让主流程更清晰。比如单独写一个calculate方法接收a、b和op,返回结果或抛出异常。这样在后续扩展平方根、取模等运算时,只需要改一个方法,而不用动输入逻辑。许多初学者喜欢把所有代码写进main,项目稍大就难以维护。
二、用if-else与switch组织分支结构
拿到运算符之后,最核心的就是分支结构。Java里可以用if-else if-else链,也可以用switch语句。对于运算符这种离散的字符值,switch可读性更好,而且在Java 7之后switch已支持String,字符自然也没问题。下面的示例用switch处理四种基本运算。
在switch中每个case后面要跟break,否则会发生穿透执行,比如输入加号却把减法也跑一遍。同时必须写default分支提示用户输入了不支持的符号。相比if判断,switch在分支多的时候更不容易漏掉条件,也方便他人快速看懂支持哪些运算。
public static double calculate(double a, double b, char op) {
double result;
switch (op) {
case '+':
result = a + b;
break;
case '-':
result = a - b;
break;
case '*':
result = a * b;
break;
case '/':
if (b == 0) {
throw new ArithmeticException("除数不能为0");
}
result = a / b;
break;
default:
throw new IllegalArgumentException("不支持的运算符: " + op);
}
return result;
}
如果坚持用if-else结构,逻辑等价但代码更长。它的优势是在需要范围判断时更灵活,比如判断数值是否落在某区间。但对于单字符运算符,switch在语义上更贴切。还要注意浮点数比较不能用==直接判断是否为0,不过除法里判断b == 0.0在常规输入下是安全的,若要求严谨可取绝对值小于1e-9。
分支结构里另一个易错点是变量作用域。如果在switch外声明result并在内部赋值,要保证每个分支都有赋值否则编译报错;也可以直接在每个case里return表达式,省去中间变量。这种写法更短,也避免了忘记赋值导致的逻辑漏洞。
三、除零异常与结果格式化输出
除法是最容易让程序崩溃的地方。当用户输入第二个数为0时,如果不处理,double相除会得到Infinity,而若将来改成int就会直接抛异常。好的做法是在运算前主动检查,并给出明确提示而不是让程序默默输出无穷。上面calculate方法里抛出的ArithmeticException就是这种思路。
在主程序调用时,应该用try-catch包住计算过程,捕获异常后打印友好信息,而不是把错误栈直接丢给用户。这样即使输入非法,程序也能继续运行或平稳退出。下面展示完整的main整合与格式化输出,用printf保留两位小数,让结果看起来更像真实计算器。
import java.util.Scanner;
public class SimpleCalculator {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入第一个数字: ");
double a = sc.nextDouble();
System.out.print("请输入运算符(+ - * /): ");
char op = sc.next().charAt(0);
System.out.print("请输入第二个数字: ");
double b = sc.nextDouble();
try {
double res = calculate(a, b, op);
System.out.printf("计算结果: %.2f%n", res);
} catch (Exception e) {
System.out.println("出错了: " + e.getMessage());
}
sc.close();
}
public static double calculate(double a, double b, char op) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/':
if (b == 0) throw new ArithmeticException("除数不能为0");
return a / b;
default:
throw new IllegalArgumentException("不支持的运算符");
}
}
}
结果格式化方面,printf里的%.2f代表保留两位小数的浮点输出,%n是跨平台换行符。如果结果本身是整数如3.00,这样显示也没问题;若想智能去掉末尾零,可以先用BigDecimal做去尾零处理,但简单计算器没必要过度设计。重点是让用户看清答案,而不是追求完美格式。
把这个例子跑起来后,你会发现它已经具备了一个迷你计算器的核心能力:读取、分支、运算、防错。后续想加功能,例如支持连续计算、增加取模%或幂运算Math.pow,都只是在switch里多写几个case。理解了运算符与分支的配合,也就打通了Java顺序、选择、循环三大逻辑中的关键一环。