news 2026/6/25 16:03:53

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第8章 第一阶段项目:命令行成绩统计器

第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 为什么总是强调类和对象。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/25 16:03:34

PCL 基于高程改进的体素滤波

目录 一、改进简介 1. 体素空间离散化 2. 基于哈希表的极值聚合 3. 结果输出 4. 与传统方法的对比 5. 参数影响 二、代码实现 三、结果展示 1. 原始点云 2. 滤波结果 一、改进简介 本文提出一种面向高程极值保留的改进体素滤波算法,旨在解决传统体素滤波因取重心或随机采样导致…

作者头像 李华
网站建设 2026/6/25 16:03:00

5步掌握Dism++:从系统清理到备份恢复的完整指南

5步掌握Dism&#xff1a;从系统清理到备份恢复的完整指南 【免费下载链接】Dism-Multi-language Dism Multi-language Support & BUG Report 项目地址: https://gitcode.com/gh_mirrors/di/Dism-Multi-language 还在为Windows系统卡顿、空间不足而烦恼吗&#xff1f…

作者头像 李华
网站建设 2026/6/25 16:01:34

Stimulsoft参数面板自动显示变量Description如何关闭?

问题背景 在 Stimulsoft 报表里&#xff0c;变量常被用作输入参数。为了让最终用户看到更友好的字段名&#xff0c;开发者通常会维护 Alias&#xff1b;而 Description 更适合放内部说明、业务解释或维护备注。 原帖用户反馈的问题是&#xff1a;从 Stimulsoft Designer、Angul…

作者头像 李华
网站建设 2026/6/25 15:48:01

诊断证明翻译怎么办理?诊断证明翻译怎么线上办理?

内容摘要&#xff1a;办理诊断证明翻译的关键在于术语严谨、格式对齐以及具备受认可的翻译资质印章。无论是用于出国就医、签证办理还是跨国保险理赔&#xff0c;准确的医学内容转换都直接影响后续流程的推进。目前&#xff0c;市面上的办理渠道主要分为线下翻译公司、网络自由…

作者头像 李华