尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

第8章 第一阶段项目:命令行成绩统计器

第8章 第一阶段项目:命令行成绩统计器
📅 发布时间:2026/6/25 16:15:32

第8章 第一阶段项目:命令行成绩统计器

第一阶段学了很多基础知识:

  • Java 程序运行。
  • 变量和类型。
  • 输入输出。
  • 条件判断。
  • 循环。
  • 方法。

如果这些知识只停留在小片段里,很容易学完就忘。项目的意义是把它们串起来。本章我们做一个命令行成绩统计器。

一、项目目标

程序运行后:

  1. 询问要输入多少个学生成绩。
  2. 逐个输入成绩。
  3. 每个成绩必须是 0 到 100 的整数。
  4. 输入非法时提示错误,并要求重新输入。
  5. 输入完成后统计:
    • 最高分。
    • 最低分。
    • 平均分。
    • 及格人数。
    • 及格率。
  6. 程序结构要拆成方法,不把所有逻辑堆在 main 里。

最终效果类似:

请输入学生人数:3 请输入第1个学生成绩:90 请输入第2个学生成绩:abc 成绩必须是整数,请重新输入 请输入第2个学生成绩:80 请输入第3个学生成绩:59 ===== 成绩统计 ===== 最高分:90 最低分:59 平均分:76.33 及格人数:2 及格率:66.67%

二、先做最小版本

第一版不处理非法输入,只跑通流程。

importjava.util.Scanner;publicclassScoreStatisticsAppV1{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.print("请输入学生人数:");intcount=scanner.nextInt();int[]scores=newint[count];for(inti=0;i<count;i++){System.out.print("请输入第"+(i+1)+"个学生成绩:");scores[i]=scanner.nextInt();}intmax=scores[0];intmin=scores[0];intsum=0;intpassCount=0;for(intscore:scores){if(score>max){max=score;}if(score<min){min=score;}if(score>=60){passCount++;}sum+=score;}doubleaverage=sum*1.0/count;doublepassRate=passCount*100.0/count;System.out.println("最高分:"+max);System.out.println("最低分:"+min);System.out.println("平均分:"+average);System.out.println("及格人数:"+passCount);System.out.println("及格率:"+passRate+"%");}}

这个版本能跑,但有问题:

  • 学生人数如果输入 0,会访问scores[0]出错。
  • 成绩如果输入 abc,会直接异常。
  • 成绩如果输入 200,也会被接受。
  • main 太长。
  • 统计逻辑没有拆方法。

项目开发通常就是这样:先跑通,再逐步加校验和结构。

三、设计程序结构

我们把程序拆成几类方法:

读取学生人数 读取一个合法成绩 判断字符串是否整数 查找最高分 查找最低分 计算平均分 统计及格人数 打印统计结果

对应方法:

readStudentCount readScore isInteger findMax findMin calculateAverage countPassed printReport

拆方法不是为了显得高级,而是为了让每段逻辑有名字、有边界。

四、完整版本代码

importjava.util.Scanner;publicclassScoreStatisticsApp{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);intstudentCount=readStudentCount(scanner);int[]scores=newint[studentCount];for(inti=0;i<studentCount;i++){scores[i]=readScore(scanner,i+1);}printReport(scores);}publicstaticintreadStudentCount(Scannerscanner){while(true){System.out.print("请输入学生人数:");Stringtext=scanner.nextLine();if(!isInteger(text)){System.out.println("学生人数必须是整数,请重新输入");continue;}intcount=Integer.parseInt(text);if(count<=0){System.out.println("学生人数必须大于0,请重新输入");continue;}returncount;}}publicstaticintreadScore(Scannerscanner,intindex){while(true){System.out.print("请输入第"+index+"个学生成绩:");Stringtext=scanner.nextLine();if(!isInteger(text)){System.out.println("成绩必须是整数,请重新输入");continue;}intscore=Integer.parseInt(text);if(score<0||score>100){System.out.println("成绩必须在0到100之间,请重新输入");continue;}returnscore;}}publicstaticbooleanisInteger(Stringtext){if(text==null||text.isEmpty()){returnfalse;}for(inti=0;i<text.length();i++){charch=text.charAt(i);if(ch<'0'||ch>'9'){returnfalse;}}returntrue;}publicstaticintfindMax(int[]scores){intmax=scores[0];for(intscore:scores){if(score>max){max=score;}}returnmax;}publicstaticintfindMin(int[]scores){intmin=scores[0];for(intscore:scores){if(score<min){min=score;}}returnmin;}publicstaticdoublecalculateAverage(int[]scores){intsum=0;for(intscore:scores){sum+=score;}returnsum*1.0/scores.length;}publicstaticintcountPassed(int[]scores){intcount=0;for(intscore:scores){if(score>=60){count++;}}returncount;}publicstaticvoidprintReport(int[]scores){intmax=findMax(scores);intmin=findMin(scores);doubleaverage=calculateAverage(scores);intpassCount=countPassed(scores);doublepassRate=passCount*100.0/scores.length;System.out.println();System.out.println("===== 成绩统计 =====");System.out.println("最高分:"+max);System.out.println("最低分:"+min);System.out.printf("平均分:%.2f%n",average);System.out.println("及格人数:"+passCount);System.out.printf("及格率:%.2f%%%n",passRate);}}

五、逐段解释

1. main 方法只保留主流程

intstudentCount=readStudentCount(scanner);int[]scores=newint[studentCount];for(inti=0;i<studentCount;i++){scores[i]=readScore(scanner,i+1);}printReport(scores);

main 读起来像流程说明:

读取学生人数 -> 创建成绩数组 -> 逐个读取成绩 -> 打印报告

这就是抽方法的好处。

2. readStudentCount 为什么用 while true

while(true){...if(不合法){continue;}returncount;}

这里的逻辑是:只要用户没输入合法人数,就一直要求重新输入。一旦合法,return count直接结束方法。

这种循环适合“直到输入合法”的场景。

3. isInteger 为什么自己写

我们先不用异常处理,是因为异常还没正式讲。第一阶段用字符判断更直观:

for(inti=0;i<text.length();i++){charch=text.charAt(i);if(ch<'0'||ch>'9'){returnfalse;}}

它逐个检查字符是否在'0'到'9'之间。

这个方法当前不支持负数,因为学生人数和成绩都不应该是负数。

4. findMax 和 findMin 为什么用 scores[0]

intmax=scores[0];

因为如果分数范围以后变了,初始值写死可能不可靠。用数组第一个元素作为初始值更通用。

本项目里学生人数已经保证大于 0,所以 scores 一定不是空数组。

5. printf 中的%%

System.out.printf("及格率:%.2f%%%n",passRate);

%.2f表示保留两位小数。
%%表示输出一个百分号。
%n表示换行。

所以这里会输出:

及格率:66.67%

六、这个项目用到了哪些知识

知识在项目中的体现
变量studentCount、scores、max、min
类型int、double、String、boolean、int[]
输入Scanner
输出print、println、printf
条件校验人数、校验成绩
循环重复输入、遍历数组
continue输入不合法时重新循环
return输入合法后返回结果
方法拆分读取、统计、输出
数组保存多个成绩

这就是阶段项目的意义:把分散知识串起来。

七、可以继续改进的地方

这个项目还不是最终工程。它还有很多可以改进的地方:

  • 支持输入学生姓名。
  • 每个学生不仅有成绩,还有学号。
  • 统计优秀人数。
  • 保存到文件。
  • 下次启动读取历史成绩。
  • 用类表示 Student。
  • 用 List 替代数组。
  • 用异常处理输入转换。

这些改进会在后续阶段逐步实现。现在不要急着一次做完。学习编程最重要的是每一步都知道自己为什么这么写。

八、常见错误

1.scanner.nextLine()读到空字符串

如果你混用nextInt()和nextLine(),容易出现换行残留。本项目统一使用nextLine(),避免这个问题。

2. 空数组访问 scores[0]

如果学生人数允许 0,findMax会出错。本项目在readStudentCount保证人数大于 0。

3. 平均分整数除法

错误:

returnsum/scores.length;

正确:

returnsum*1.0/scores.length;

4. 忘记 return 导致循环停不下来

合法输入后必须 return,否则 while true 会继续。

5. 方法拆太碎或不拆

所有逻辑堆 main 里难读;但每一行都拆方法也没必要。拆方法的原则是:这段逻辑有明确名字,并且能独立理解。

九、本章练习

  1. 增加优秀人数统计:分数大于等于 90 算优秀。

  2. 增加不及格人数统计。

  3. 修改输出,让平均分和及格率都保留 1 位小数。

  4. 增加输入班级名称,并在报告中输出。

  5. 尝试把printReport再拆成:

printBasicReport printPassReport
  1. 思考:如果要保存学生姓名和成绩,数组还够不够用?

十、第一阶段总结

完成这个项目,说明你已经能把第一阶段的基础知识串起来。

你应该已经具备:

  • 编写 main 程序。
  • 使用变量和类型。
  • 从命令行读取输入。
  • 使用条件校验数据。
  • 使用循环重复处理。
  • 使用数组保存一组数据。
  • 使用方法拆分逻辑。
  • 阅读基础错误并修复。

这还不是 Java 的全部,但它是继续学习面向对象的前提。下一阶段会把“学生成绩”这种散落的数据升级成对象,比如Student类。到那时,你会看到 Java 为什么总是强调类和对象。

相关新闻

  • 5个实用技巧:使用Dism++免费系统优化工具快速提升电脑性能
  • 【DDS】入门基础
  • 3分钟终极指南:如何免费激活Windows和Office的完整教程

最新新闻

  • 如何用Buzz离线语音转文字工具彻底解放你的音频处理工作流?
  • Windows 11终极清理指南:3步免费移除系统臃肿
  • 物联网边缘安全:基于NXP A71CH安全元件的硬件信任根实践
  • FFmpegGUI:三步告别复杂命令行,开启高效视频处理新时代
  • 技术线上面试代码写完就以为通关?留学生利用黑盒测试自证风控「蒸汽教育分享」
  • MCP16311/2开关电源实战:热计算与PCB布局在LED驱动中的关键应用

日新闻

  • Qwen2.5-Turbo百万上下文实战指南:百炼平台长文本处理全解析
  • 怎么监控对标账号更新,2026年作者监控工作流,5款深度对比
  • EdgeRemover:专业级Windows Edge浏览器管理工具,彻底解决顽固软件卸载难题

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号