当前位置: 首页 > news >正文

三次作业集的总结

本文基于三次递进式Java编程作业的完整代码,从知识点覆盖、题量与难度演进、典型“采坑”案例、可持续改进方向以及教学组织建议五个维度进行深度总结。三次作业分别模拟了航班货物配载、多货舱货物管理、旅客行李及重心平衡计算三个业务场景,难度逐次提升,充分暴露了从基础语法到面向对象设计、异常处理、业务建模等不同层次的问题。以下分析均结合具体代码片段、测试用例和类设计结构,力求详实、可复现。

一、三次作业知识点、题量、难度综合对比
作业 核心知识点 新增技术点 代码行数(不含空行) 类数量 题量 主观难度
第一次 类与对象、数组、选择排序、Scanner、循环、条件判断 无 约120行 6 1 入门
第二次 内部类、对象数组、多货舱、装载匹配、浮点精度 多对象协作、装载失败处理(不完整) 约210行 7 1 中等偏下
第三次 ArrayList、力臂与重心计算、输入验证、异常处理雏形 旅客行李建模、物理公式、批量输入校验 约280行 9 1 中等
分析:

二、采坑心得:三次作业中的典型错误与数据验证

  1. 第一次作业:Scanner的换行陷阱与排序副作用
    错误场景:
    在Input.readp()方法中:

java
for (int i = 0; i < n; i++) {
car[i] = new Cargo();
scanner.nextLine(); // 吸收换行
car[i].cargoname = scanner.nextLine();
car[i].cargoweight = scanner.nextDouble();
}
当输入货物名称包含空格(如“Apple Juice”)时,nextLine()会将整行读入,看似正确。但若用户输入格式为:

text
CA1234
5000
2
Laptop 15.5
Monitor 8.2
此时第一个nextLine()会读取“Laptop 15.5”整行,导致cargoname得到“Laptop 15.5”,下一个nextDouble()则无法解析。正确做法:统一使用next()读取无空格标识符,或要求每行一个独立字段。

排序副作用:
Paixu.paixu()直接修改传入数组,若后续需要原始顺序(如按货物ID输出),则无法满足。改进:方法应返回新数组,或明确在注释中说明“会修改原数组”。

测试用例验证:
输入负数货物数量-1,程序创建数组大小为-1,抛出NegativeArraySizeException。缺失校验:应在读取n后检查n>0。

  1. 第二次作业:货物丢失与浮点数比较不一致
    典型漏洞:装载失败导致货物“凭空消失”
    代码逻辑:

java
if (totalWeight + cargo.weight <= maxWeight + 1e-9) {
this.cargo[currentCount] = cargo;
currentCount++;
System.out.printf("成功");
} else {
System.out.printf("失败");
// 货物未被保存,也没有任何失败列表
}
重现步骤:

货舱H1最大载重1000kg,已有950kg。

货物C999重100kg,目标舱位H1。

装载失败,输出“失败”,但C999未存入任何集合。

最终总重量计算为950kg(丢失100kg),航班本应超载却被判为正常。

改进方案:

在CargoCompartment中增加List failedCargos。

或在main中维护一个unloaded列表,装载失败时加入该列表,最后输出警告并拒绝起飞。

浮点数比较问题:
两处比较逻辑不一致:

装载时:totalWeight + cargo.weight <= maxWeight + 1e-9

状态输出:current <= comp.maxWeight + 1e-9
虽然实际效果相近,但语义不统一。应提取方法:

java
private static boolean isWithinLimit(double current, double max, double eps) {
return current - max <= eps;
}
3. 第三次作业:硬编码与输入顺序的脆弱性
硬编码业务参数:

java
compartments[0].setIdAndArm(1, 12.0);
compartments[1].setIdAndArm(2, 22.0);
// 以及空机重量40000kg、空机力臂16.25、旅客力臂18.0
若题目要求改为3个货舱或不同机型,必须修改源码。改进:这些参数应从输入读取或使用配置文件。

输入顺序脆弱:
输入必须严格按“航班号 → 货舱1尺寸/载重 → 货舱2尺寸/载重 → 旅客行李数量 → 行李重量列表 → 货物数量m → 分割点p → m条货物”的顺序。一旦顺序错误(如先输入货物再输入旅客),程序会异常或静默出错。改进:使用带提示的交互式输入,或采用更健壮的解析器(如逐行读取并标记)。

行李重量未做合理性校验:
虽然InputValidator.readDouble()禁止负数,但未检查行李是否过大(例如500kg的行李明显不合理)。建议:增加if(weight > 100) System.out.println(“警告:行李超重”),并允许用户选择是否继续。

三、类设计与流程图分析(以第三次作业为例)
类图
text
Main (含main)
├─ InputValidator
│ ├─ readFlight() → Flight
│ ├─ readCargoCompartments(int) → CargoCompartment[]
│ ├─ readCargo(int) → Cargo[]
│ └─ readInt() / readDouble()
├─ Flight
│ ├─ id: String
│ ├─ passengerList: List
│ ├─ compartments: CargoCompartment[]
│ ├─ addPassenger(Passenger)
│ ├─ getTotalPassengerWeight()
│ └─ setCompartments(...)
├─ Passenger
│ ├─ luggage: Luggage
│ └─ (隐含标准体重75kg)
├─ Luggage (仅包装weight)
├─ Cargo (id, weight)
├─ CargoCompartment
│ ├─ id, maxWeight, arm, position, cargoList: List
│ ├─ addCargo(Cargo): boolean
│ ├─ getCurrentWeight(), getMoment()
├─ Position (rows, cols)
└─ WeightBalanceCalculator (静态方法 generateLoadSheet)
设计缺陷:

Passenger中的name字段从未使用,应删除或完善。

Luggage类仅包装一个double,过度设计,可合并到Passenger。

WeightBalanceCalculator与Flight耦合过紧(直接访问passengerList和compartments),可改为传入必要参数,提高可测试性。

核心流程图(第三次作业)
text
开始

读取航班号

读取2个货舱的(rows, cols, maxWeight)

设置货舱ID和力臂(硬编码12.0/22.0)

读取旅客数量n

循环n次: 读取行李重量 → 创建Passenger → flight.addPassenger

读取货物数量m

读取分割点p (前p件货物装入前货舱,其余装入后货舱)

读取m个货物(id, weight)

循环前p个货物 → compartments[0].addCargo

循环剩余货物 → compartments[1].addCargo

调用WeightBalanceCalculator.generateLoadSheet

计算旅客总重量(75人数 + 行李总和) 及 力矩(18.0)

计算前/后货舱重量及力矩(重量力臂)

总重量 = 40000 + 旅客总重 + 货物总重
总力矩 = 40000
16.25 + 旅客力矩 + 货物力矩

实际重心 = 总力矩/总重量
重心百分比MAC = ((重心-15)/5)*100

判断是否在[25%, 38%]区间 → 安全/危险

输出舱单

结束

四、改进建议(可持续重构方向)

  1. 消除硬编码与魔法数
    建立AircraftConfig类,包含空机重量、空机力臂、旅客标准重量、旅客平均力臂、前后货舱力臂等。

从输入文件或命令行参数加载配置,支持不同机型。

  1. 强化错误处理与恢复机制
    所有scanner.nextXxx()应捕获InputMismatchException并清空缓冲区后重试。

对于装载失败,应收集失败货物列表,最后询问用户是否调整或取消航班。

  1. 提升可测试性
    将WeightBalanceCalculator.generateLoadSheet拆分为多个小方法:calcPassengerTotal、calcCargoTotal、calcCG、formatOutput,每个方法可单独单元测试。

使用依赖注入(例如通过构造函数传入PrintStream输出)以便于测试输出内容。

  1. 优化数据结构
    第二次作业中CargoCompartment使用Cargo[]固定数组 → 统一改为ArrayList

第三次作业中Flight的passengerList用ArrayList很好,但compartments仍用固定数组,可改为List

  1. 增加业务规则校验
    旅客行李重量上限(如30kg),超额需额外计费或警告。

货物重量不能超过单件上限(如500kg)。

重心百分比超出安全范围时,输出具体调整建议(如“将后货舱货物移至前货舱Xkg”)。

  1. 代码复用
    第一次和第二次作业都有排序代码,第三次没有。可提取CargoSorter工具类,支持按重量、按ID等多种排序。

输入验证逻辑在第三次作业中已较好封装,可前移到前两次作业的重构版本中。

五、三次作业整体总结与反思
学到了什么
输入处理的演进
从第一次的“莽撞读取”到第三次的带类型检查和负数过滤,深刻理解了Scanner的缓冲区机制以及防御式编程的重要性。以后任何读取用户输入的地方,都会考虑“如果用户输入的不是数字怎么办”、“如果输入负数怎么办”。

对象职责划分
第一次作业将所有逻辑塞进main;第二次作业开始有LoadDispatcher、InputValidator;第三次作业独立出WeightBalanceCalculator。虽然仍有改进空间,但已经体会到了单一职责原则的好处:修改重心计算公式时,不需要改动输入和输出代码。

物理公式编程
第三次作业的力矩和重心百分比计算,将实际航空配载知识转化为代码,体会到了“专业领域知识 + 编程”的乐趣。同时理解了浮点数运算的精度问题,学会了使用容差比较。

错误处理意识
第二次作业的“货物丢失”漏洞给我上了一课:程序表面“正常运行”,但数据已经错误。必须对每个操作设想“如果失败会发生什么”,并显式处理失败路径。

需要进一步学习及研究的内容
异常处理体系:自定义业务异常(如OverloadException、CargoNotLoadedException),并学习try-with-resources。

设计模式:工厂模式用于创建不同货舱类型,策略模式用于动态选择装载算法(按重量优先、按体积优先等)。

单元测试:使用JUnit测试addCargo在边界情况下的行为,测试重心计算公式的正确性。

日志框架:使用SLF4J替代System.out.println,实现日志级别控制。

持久化:将航班配载数据存入数据库(如SQLite),实现历史查询。

对教学组织的具体建议
作业反馈机制
每次作业后,公布一份官方“常见错误清单”和“优秀代码示例”,比单纯给分数更能促进学生进步。例如第二次作业后指出“货物丢失”问题,并展示如何用ArrayList failed解决。

课上互动
选取2-3份学生代码(征得同意),进行现场重构演示。例如将第三次作业的硬编码力臂改为配置文件读取,学生能直观感受重构的价值。

实验课设计
增加“结对编程”环节:两人一组,一人写单元测试,一人写实现,轮换角色。这能培养测试驱动开发的习惯,且减少作业抄袭。

难度梯度微调
第二次作业到第三次作业的跨度略大(突然引入力矩和百分比)。建议在第二次和第三次之间增加一次小作业:只要求计算重心(无旅客),帮助学生过渡。

评分标准透明化
将“代码质量”细分为:命名规范(10%)、注释(5%)、异常处理(10%)、无硬编码(10%)、可扩展性(5%)。让学生清楚不仅仅是“能跑就行”。

课程资源
提供本次作业中发现的nextLine陷阱、浮点数比较、集合遍历时的并发修改等。

最终结语
三次作业虽然代码总量不大(累计约600行),但覆盖了从语法到设计、从功能到健壮性、从业务到物理公式的多个层次。通过亲身编码、踩坑、反思、重构,我收获了比单纯听课更深刻的经验。特别是第二次作业的“货物丢失”和第三次作业的“硬编码力臂”,让我意识到:程序不仅要对正确输入给出正确输出,更要对错误输入和异常情况给出合理处理,且要易于变化。希望未来的作业能继续保持这种“小步快跑、逐级递增”的风格,并配合更细致的代码评审指导,帮助更多同学跨越从“会写”到“写好”的鸿沟。

http://www.jsqmd.com/news/838941/

相关文章:

  • 小红书怎么关闭下载水印?2026最新方法盘点|创作者无水印设置+工具方案全覆盖 - 爱上科技热点
  • Audacity音频编辑神器:三步开启专业音频处理之旅
  • 如何高效使用BilibiliDown音频提取:从B站视频中无损提取音乐的完整指南
  • 一键封装成EXE!让Windows命令行像Linux一样直接敲‘binwalk’的懒人方案
  • 经营分析别再只会同环比,手把手教你开好经营分析会
  • 微信客户端自动化工具开发指南:从协议模拟到风险控制
  • 开发AI应用时如何利用Taotoken快速切换模型进行A B测试
  • 如何快速解决AKShare股票数据获取失败:完整的数据采集优化指南
  • 阶段与关口:项目管理中的核心触发器与决策机制解析
  • 2026年苏州同居关系纠纷律所排行:专业能力与实战案例对比 - 奔跑123
  • 2026年陕西省人力分析共享中心及人力资源数智化服务商推荐榜 - 深度智识库
  • HDU5628 Clarke and math 题解 狄利克雷卷积+快速幂
  • 告别网盘下载烦恼:LinkSwift跨平台直链解析工具完全指南
  • 怎样轻松安装ModTheSpire:3个秘诀让你快速上手杀戮尖塔模组管理
  • Ubuntu下CLion从安装到调优:告别卡顿与配置难题
  • Hive 3.1.2 避坑指南:手把手解决‘Metastore未初始化’及分区表数据导入那些事儿
  • 使用Taotoken为Claude Code配置稳定API解决封号困扰
  • 你的Mac存储空间去哪了?Pearcleaner帮你找回丢失的GB
  • ART-Pi软件模拟I2C驱动MPU6050:RT-Thread下的灵活通信方案
  • 拯救论文AI检测标红!2026实测5款降重平台,注入“真实感”的手改全攻略
  • 2026年学术期刊代理行业AI搜索优化服务商选型分析与优质机构推荐 - 产业观察网
  • 收藏!小白程序员必看:读懂AI岗位JD,精准投递不陪跑
  • 终极指南:在Windows上直接安装安卓APK的3大优势与6个实用技巧
  • 如何快速解决AKShare股票数据获取失败的5大实用技巧
  • 英雄联盟内存换肤神器:R3nzSkin全攻略
  • 学Simulink--基于自抗扰控制(ADRC)的电动汽车电机抗负载扰动仿真
  • 3分钟免费安装OBS背景移除插件:无需绿幕的AI虚拟背景终极指南
  • RIS辅助无人机通信的能效优化与深度强化学习应用
  • 国产车载RISC-V AI MCU技术解析:从架构创新到生态构建
  • Windows逆向工程实战:揭秘微信QQ消息防撤回的核心技术与实现