综合练习:命令行小工具
这是什么:BMI 健康计算器 = 输入身高体重,自动算出 BMI 并给出健康评级的命令行小工具。
为什么用:学了变量、分支、循环、数组、方法、字符串,是时候全串起来了。零散练过不代表会用,把它们拧成一个真能跑的东西,才算学到位。
如何用:本章先照着示范项目敲完一个能跑的版本,再去挑战后面七关的练习题库。
需求
- 提示用户输入体重(公斤)和身高(米)
- 计算 BMI = 体重 ÷ 身高²
- 按国内常用标准评级:偏瘦 <18.5,正常 18.5~24,偏胖 24~28,肥胖 ≥28
完整代码
新建 BmiCalculator.java:
import java.util.Scanner; // 引入"扫描器",专门读键盘输入
public class BmiCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入体重(公斤):");
double weight = scanner.nextDouble(); // 程序会停在这里等你输入
System.out.print("请输入身高(米):");
double height = scanner.nextDouble();
double bmi = calcBmi(weight, height); // 调用方法算 BMI
System.out.printf("你的 BMI 是:%.1f%n", bmi); // 保留 1 位小数
System.out.println("评级:" + classify(bmi));
scanner.close();
}
// 方法一:算 BMI(参数进,结果出)
static double calcBmi(double weight, double height) {
return weight / (height * height);
}
// 方法二:根据 BMI 评级(if / else if 分支)
static String classify(double bmi) {
if (bmi < 18.5) {
return "偏瘦";
} else if (bmi < 24) {
return "正常";
} else if (bmi < 28) {
return "偏胖";
} else {
return "肥胖";
}
}
}
运行效果
在文件所在文件夹打开命令行,运行:
java BmiCalculator.java
然后在提示处输入数字(下面演示输入 70 和 1.75):
请输入体重(公斤):70
请输入身高(米):1.75
你的 BMI 是:22.9
评级:正常
70 ÷ (1.75 × 1.75) ≈ 22.86,保留一位小数是 22.9,落在 18.5~24 区间 → 正常 ✅
用到的知识全回顾
| 知识点 | 在哪用到 |
|---|---|
| 变量与类型 | double weight、String 返回值 |
| 方法与返回值 | calcBmi、classify |
| if / else if 分支 | classify 的评级逻辑 |
| 字符串拼接 | "评级:" + classify(bmi) |
| Scanner | 读用户键盘输入 |
| printf 格式化 | %.1f 保留 1 位小数 |
一个值得留意的工程细节:这个程序把"算"(calcBmi)和"评"(classify)拆成了两个方法,main 只负责串流程。职责单一的方法才有第二次生命——哪天评级标准改了,只动 classify;哪天想算别人的,只改输入。这就是方法章说的"拆块"思维第一次实战。
练习题库:七关打怪
下面 7 道题按难度递增,每题给出需求、提示、参考答案。强烈建议:先自己写,写不出来再看提示,运行成功后再对照参考答案找差距。所有题目都只需要"一个 .java 文件 + java 文件名.java"就能跑。
怎么刷这套题,给你三条纪律:
- 先跑通,再优化。第一目标是程序"对了"——输入什么输出什么全符合预期;对齐参考答案的风格是第二遍的事。
- 报错自己先读一遍。把报错里的行号、类型名圈出来,尝试自己翻译成中文再求助。练出"读报错"的手感,比多做两道题更值钱。
- 别复制粘贴参考答案。手敲一遍,哪怕敲错再改——手指的记忆比眼睛可靠,这是所有老程序员的共识。
星级怎么理解:★☆☆ 是"照着骨架改"的热身,★★☆ 需要"自己搭循环和分支的组合",★★★ 要求"多招连用 + 边界处理"。卡在某一关超过半小时,看提示再继续;卡超过一小时,直接看答案,理解后关掉答案重写一遍。
练习 1:温度转换器 ★☆☆
考察点:Scanner 读输入、方法封装、printf 保留小数——BMI 计算器的等比缩小版。
需求:让用户输入摄氏温度,输出对应的华氏温度(公式 f = c × 1.8 + 32),保留 1 位小数。
提示:照着 BMI 计算器的骨架改:Scanner 读一个 double → 交给方法算 → printf 输出。三步一个不多。
参考答案:
import java.util.Scanner;
public class TempConverter {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入摄氏温度:");
double c = scanner.nextDouble();
System.out.printf("华氏温度:%.1f%n", celsiusToFahrenheit(c));
scanner.close();
}
static double celsiusToFahrenheit(double c) {
return c * 1.8 + 32;
}
}
运行效果(输入 37):
请输入摄氏温度:37
华氏温度:98.6
练习 2:奇偶裁判 ★☆☆
考察点:取余运算、if / else 双判断、else if / else 兜底结构。
需求:用户输入一个整数,程序判断它是奇数还是偶数;顺便判断它是不是正数。
提示:判断奇偶用取余运算 n % 2——余 0 是偶数;判断正负用和 0 比较。两个 if 各管一件事。
参考答案:
import java.util.Scanner;
public class OddEven {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个整数:");
int n = scanner.nextInt();
if (n % 2 == 0) {
System.out.println(n + " 是偶数");
} else {
System.out.println(n + " 是奇数");
}
if (n > 0) {
System.out.println(n + " 是正数");
} else if (n < 0) {
System.out.println(n + " 是负数");
} else {
System.out.println("它是 0,不好不坏");
}
scanner.close();
}
}
运行效果(输入 7):
请输入一个整数:7
7 是奇数
7 是正数
练习 3:九九乘法表 ★★☆
考察点:嵌套 for、内外层变量分工、print / println 组合。
需求:用嵌套 for 循环打印完整的九九乘法表(9 行)。
提示:外层 i 管行(1 到 9),内层 j 管每行打几项(1 到 i);print 拼行、\t 对齐、行尾 println 换行。流程控制章写过 3 行版,这题只是把 3 改成 9。
参考答案:
public class NineTable {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "×" + i + "=" + (i * j) + "\t");
}
System.out.println();
}
}
}
运行效果(节选前 3 行):
1×1=1
1×2=2 2×2=4
1×3=3 2×3=6 3×3=9
练习 4:班级成绩统计员 ★★☆
考察点:数组遍历、擂主法求最值、整数除法强转、计数器模式。
需求:程序里写死一个存 5 个成绩的数组,输出:最高分、最低分、平均分(保留 1 位小数)、超过 85 分的人数。
提示:求最值用"擂主法"(先设第 1 个最大);平均分记得把 sum 强转成 double 再除;数人数用一个计数器变量,循环里 if 命中就 count++。
参考答案:
public class ScoreStats {
public static void main(String[] args) {
int[] scores = {90, 85, 77, 68, 95};
int max = scores[0];
int min = scores[0];
int sum = 0;
int count = 0;
for (int i = 0; i < scores.length; i++) {
if (scores[i] > max) {
max = scores[i];
}
if (scores[i] < min) {
min = scores[i];
}
sum += scores[i];
if (scores[i] > 85) {
count++;
}
}
double avg = (double) sum / scores.length;
System.out.println("最高分:" + max);
System.out.println("最低分:" + min);
System.out.printf("平均分:%.1f%n", avg);
System.out.println("超过 85 分的人数:" + count);
}
}
输出:
最高分:95
最低分:68
平均分:83.0
超过 85 分的人数:2
练习 5:句词倒序器 ★★☆
考察点:字符串下标倒序遍历、charAt 拼接、StringBuilder.reverse 现成工具。
需求:用户输入一个单词,程序倒着打印它(比如输入 ribbit 输出 tibbir)。用两种写法:① StringBuilder 的 reverse;② 手写循环倒着遍历。
提示:写法②用 for (int i = s.length() - 1; i >= 0; i--) 从尾往头 charAt 取字符拼接。
参考答案:
import java.util.Scanner;
public class ReverseWord {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个单词:");
String s = scanner.next();
// 写法一:现成工具
StringBuilder sb = new StringBuilder(s);
System.out.println("工具版:" + sb.reverse());
// 写法二:手写循环,从最后一个字符往前取
String result = "";
for (int i = s.length() - 1; i >= 0; i--) {
result += s.charAt(i);
}
System.out.println("手写版:" + result);
scanner.close();
}
}
运行效果(输入 ribbit):
请输入一个单词:ribbit
工具版:tibbir
手写版:tibbir
练习 6:猜数字游戏 ★★★
考察点:随机数生成、while 条件循环、break 退出、计数统计——第一个"有游戏感"的程序。
需求:程序暗中生成一个 1~100 的随机数,用户反复猜,每次提示"大了 / 小了 / 猜对了",猜中后告诉用户一共猜了几次。
提示:随机数用 (int) (Math.random() * 100) + 1(Math.random() 生成 0 到 1 之间的小数);循环用 while(不知道几轮); Scanner 的 nextInt() 每次读一个数。
参考答案:
import java.util.Scanner;
public class GuessNumber {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int answer = (int) (Math.random() * 100) + 1;
int count = 0;
System.out.println("我想好了一个 1~100 的数,猜猜看!");
while (true) {
System.out.print("你猜:");
int guess = scanner.nextInt();
count++;
if (guess > answer) {
System.out.println("大了");
} else if (guess < answer) {
System.out.println("小了");
} else {
System.out.println("猜对了!共猜了 " + count + " 次");
break; // 猜中收工,跳出循环
}
}
scanner.close();
}
}
运行效果(答案 42 的演示局):
我想好了一个 1~100 的数,猜猜看!
你猜:50
大了
你猜:25
小了
你猜:42
猜对了!共猜了 3 次
这题首次把"随机数、条件循环、分支、计数"捏在一个程序里,是基础篇的综合大考。while (true) 配 break 是"无限轮询直到命中"的标准写法,工作代码里也常见。
练习 7:菜单计算器 ★★★
考察点:switch 字符串分发、多方法协作、除零边界防护、提前 return 结束流程。
需求:用户输入两个数和一个运算符(+ - * /),程序用 switch 分发到对应方法算结果;除法要防住除数为 0 的情况。
提示:四个方法 add / sub / mul / div 各管一种运算;div 里先判断除数是否为 0;switch 的 case 标签用字符串(case "+":)完全合法。
参考答案:
import java.util.Scanner;
public class MenuCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入第一个数:");
double a = scanner.nextDouble();
System.out.print("请输入运算符(+ - * /):");
String op = scanner.next();
System.out.print("请输入第二个数:");
double b = scanner.nextDouble();
double result;
switch (op) {
case "+":
result = add(a, b);
break;
case "-":
result = sub(a, b);
break;
case "*":
result = mul(a, b);
break;
case "/":
if (b == 0) {
System.out.println("除数不能为 0!");
scanner.close();
return; // 直接结束程序
}
result = div(a, b);
break;
default:
System.out.println("不认识的运算符:" + op);
scanner.close();
return;
}
System.out.println("结果:" + result);
scanner.close();
}
static double add(double a, double b) { return a + b; }
static double sub(double a, double b) { return a - b; }
static double mul(double a, double b) { return a * b; }
static double div(double a, double b) { return a / b; }
}
运行效果(输入 10、/、4):
请输入第一个数:10
请输入运算符(+ - * /):/
请输入第二个数:4
结果:2.5
毕业自检清单
七关刷完,对照下面这张清单验收——每一条都能答"是",就放心进入面向对象篇:
| 自检项 | 达标标准 |
|---|---|
| 能独立写出 main 骨架 | 不看资料敲出类 + main 框架 |
| 变量类型选得对 | 看到"价格 / 是否 / 姓名"能秒选类型 |
| 三种循环都用过 | 知道 for / while / do-while 各自的舒适区 |
| 数组会遍历会统计 | 求和、求最值、计数不查资料 |
| 方法会拆会调 | 一个小程序至少拆出 2 个自定义方法 |
| 字符串不踩 == | 判相等条件反射写 equals |
| 报错不慌 | 越界、除零、空指针都能读着报错修好 |
卡在哪一条,就回哪一章的"动手改"再练一轮——比硬闯下一关更省时间。练习的意义不在"做过",在"做过之后代码变利索了":同样的题第二遍写,如果行数更少、报错更少,那就是真的进步。
记忆口诀
Scanner 读输入,方法分好工,分支定评级——小工具 = 变量 + 分支 + 方法。
记忆锚点:写小程序的万能配方——输入(Scanner 读进来)、加工(方法分块算)、输出(println / printf 报出去)。所有练习题都是这三步的不同排列组合,配方在手,题题能拆。
动手改
- 加一条贴心提示:评级为"偏瘦"或"偏胖"时,多打印一句建议(比如"多吃点,多动动")
- 改造成循环版:算完问"继续吗?(y/n)",输入 y 就再来一轮(提示:do-while)
- 给猜数字游戏加上次数上限:最多猜 7 次,超了就公布答案(提示:循环条件
count < 7) - 给成绩统计员加一关:把数组从小到大排序后打印(提示:
Arrays.sort) - 挑战:把菜单计算器也改成循环版,算完一轮继续收下一个算式,输入
q退出
Java 基础毕业 🎉 下一站 面向对象,Java 的主战场