🐸 青蛙编程网
首页 / Java / Java 基础 / 8. 综合练习

综合练习:命令行小工具

这是什么:BMI 健康计算器 = 输入身高体重,自动算出 BMI 并给出健康评级的命令行小工具。

为什么用:学了变量、分支、循环、数组、方法、字符串,是时候全串起来了。零散练过不代表会用,把它们拧成一个真能跑的东西,才算学到位。

如何用:本章先照着示范项目敲完一个能跑的版本,再去挑战后面七关的练习题库。

需求

  1. 提示用户输入体重(公斤)和身高(米)
  2. 计算 BMI = 体重 ÷ 身高²
  3. 按国内常用标准评级:偏瘦 <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. 先跑通,再优化。第一目标是程序"对了"——输入什么输出什么全符合预期;对齐参考答案的风格是第二遍的事。
  2. 报错自己先读一遍。把报错里的行号、类型名圈出来,尝试自己翻译成中文再求助。练出"读报错"的手感,比多做两道题更值钱。
  3. 别复制粘贴参考答案。手敲一遍,哪怕敲错再改——手指的记忆比眼睛可靠,这是所有老程序员的共识。

星级怎么理解:★☆☆ 是"照着骨架改"的热身,★★☆ 需要"自己搭循环和分支的组合",★★★ 要求"多招连用 + 边界处理"。卡在某一关超过半小时,看提示再继续;卡超过一小时,直接看答案,理解后关掉答案重写一遍。

练习 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 报出去)。所有练习题都是这三步的不同排列组合,配方在手,题题能拆。

动手改

  1. 加一条贴心提示:评级为"偏瘦"或"偏胖"时,多打印一句建议(比如"多吃点,多动动")
  2. 改造成循环版:算完问"继续吗?(y/n)",输入 y 就再来一轮(提示:do-while)
  3. 给猜数字游戏加上次数上限:最多猜 7 次,超了就公布答案(提示:循环条件 count < 7)
  4. 给成绩统计员加一关:把数组从小到大排序后打印(提示:Arrays.sort)
  5. 挑战:把菜单计算器也改成循环版,算完一轮继续收下一个算式,输入 q 退出

Java 基础毕业 🎉 下一站 面向对象,Java 的主战场

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。