Java实现答题判题程序

一、前言

本文介绍了如何使用Java设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。本次编程任务通过三次作业实现了从基本的题目管理到完整的测试系统的设计。
第一次作业主要实现了题目信息、试卷信息和答卷信息的基本处理,包括输入解析、数据存储和简单的判题逻辑。
第二次作业在此基础上增加了学生信息的处理,要求将学生信息与答卷信息关联,并在校验和输出时带上学生的相关信息。
第三次作业进一步引入了题目删除的功能,要求处理题目删除后对题目显示、答案判断及得分计算的影响,并处理各种异常情况,如题目引用错误和格式错误等。
随着任务的进展,难度逐步增加,从基本的数据结构设计和逻辑处理,到更复杂的关联数据管理、异常处理及输出格式控制。这一系列任务不仅涵盖了输入输出的基本技能,还要求具备良好的数据管理和逻辑设计能力,最终形成一个功能完备的小型测试系统。

二、设计与分析

建立框架:

  1. 类定义
    (1)Question 类:
    用于表示一个题目,包含题目编号 (number)、题目内容 (content) 和标准答案 (standardAnswer)。
    提供了一个 judgeAnswer 方法来判断答案是否正确。

(2)Exam 类:
用于表示一套题目集合,包含一个题目数组 (questions) 和题目数量 (count)。
提供方法 saveQuestion 来保存题目。
提供方法 getQuestions 返回排序后的题目数组。
提供方法 getCount 获取题目数量。

(3)Paper 类:
用于表示一份答卷,包含一个考试对象 (exam)、答案数组 (answers) 和判断结果数组 (judgments)。
提供方法 saveAnswer 来保存答案。
提供方法 judgeAnswers 来判断答案是否正确。
提供方法 displayAnswersAndJudgments 来显示题目内容、答案和判断结果。
提供方法 outputJudgments 来输出判断结果。

(4)设计类图如下:

  1. 主程序逻辑
    主函数 (main 方法):
    初始化 Scanner 对象用于读取输入。
    读取题目数量,并创建一个 Exam 对象。
    逐行读取题目信息,并创建 Question 对象,保存到 Exam 中。
    读取答题信息,并创建一个 Paper 对象。
    解析答题信息,并保存到 Paper 中。
    调用 judgeAnswers 方法进行答案判断。
    显示答题信息和判断结果。

  2. 代码实现细节
    (1)输入处理:
    使用 Scanner 类来读取输入。
    读取题目数量,并根据数量初始化 Exam 对象。
    逐行读取题目信息,使用正则表达式或字符串分割来解析题目编号、题目内容和标准答案。
    创建 Question 对象,并保存到 Exam 对象中。

(2)题目保存:
Exam 类的 saveQuestion 方法用于保存题目到数组中,根据题目编号进行索引。

(3)排序题目:
Exam 类的 getQuestions 方法返回排序后的题目数组,确保题目按照编号顺序排列。

(4)答案保存与判断:
Paper 类的 saveAnswer 方法用于保存答案到数组中。
Paper 类的 judgeAnswers 方法遍历题目数组,并调用 Question 类的 judgeAnswer 方法来判断答案是否正确。

(5)输出结果:
Paper 类的 displayAnswersAndJudgments 方法用于输出题目内容、答案和判断结果。
Paper 类的 outputJudgments 方法用于输出判断结果。

第一次作业:
输入:题目数量、题目内容(包括题号、题目内容、标准答案)、答题信息。
输出:题目数量、答题信息(题目内容 + 答案)、判题信息(判断每个答案是否正确)。
要求:程序需要处理输入的题目信息和答题信息,并根据标准答案判断答题结果。题目和答案的顺序可以不同,但答案的顺序必须与题号对应。

第二次作业:
在第一次作业上修改部分:
1.处理试卷信息:
代码中定义了 TestPaper 类来存储试卷信息,包括试卷号和每道题的分值。
在主函数中,通过读取输入行并解析,将试卷信息存储到 HashMap<String, TestPaper> 中。

2.处理总分警示:
在主函数中,遍历 HashMap 中的每份试卷,检查总分是否为100分,并将警告信息存储到 List 中。

3.处理答案数量不足的情况:
在处理答卷时,如果输入的答案信息少于试卷的题目数量,没有答案信息的题目输出 "answer is null"。
多余的答案信息在代码中被忽略,即只处理有效范围内的答案。

4.输出判分信息:
输出格式包含每道题的得分以及总分。
使用 StringBuilder 来构造输出字符串,确保格式正确。

5.提示错误的试卷号:
如果输入的答案信息中的试卷号不存在,则输出提示信息 "The test paper number does not exist"。

第三次作业:
增补或修改的部分:

  1. 学生信息处理
    在代码中,students 变量是一个 HashMap<String, String>,用来存储学生的学号和姓名。这是通过以下方式实现的:
else if (line.startsWith("#X:")) {String[] parts = line.split(" ");String studentId = parts[0].split(":")[1].trim();String studentName = parts[1].split("-")[0].trim();students.put(studentId, studentName);
}

这里,#X: 开头的行被解析成学号和姓名,并存储在 students 映射中。

  1. 删除题目信息处理
    在代码中,deletedQuestions 是一个 HashSet,用来存储被删除的题号。这是通过以下方式实现的:
    else if (line.startsWith("#D:")) {
    String parts = line.split("-")[1].trim();
    deletedQuestions.add(parts);
    }
    这里,#D: 开头的行被解析成题号,并添加到 deletedQuestions 集合中。

  2. 试卷号引用错误提示输出
    在处理 #S: 开头的行时,会检查试卷号是否存在:

if (!testPapers.containsKey(paperId)) {resultsToOutput.add("The test paper number does not exist");continue;
}

如果不存在,则输出 "The test paper number does not exist" 并继续处理下一行。

  1. 学号引用错误提示信息
    在处理每份答卷时,会检查学号是否存在:
    String studentName = students.get(studentId);
if (studentName == null) {resultsToOutput.add(studentId + " not found");
} else {resultsToOutput.add(studentId + " " + studentName + ": " + finalScores + "~" + totalScore);
}

如果学号不存在,则输出 "studentId not found",否则输出学号、姓名、得分和总分。

  1. 题目引用错误提示信息
    在处理每份答卷时,会检查题目是否存在:
Question question = questions.stream().filter(q -> q.getNumber().equals(questionNumber)).findFirst().orElse(null);if (question == null) {questionResults.add("non-existent question~0");scoresReport.append("0 ");continue;
}

如果题目不存在,则输出 "non-existent question~0"。

  1. 输出部分
    最后,所有的输出信息都被收集到 resultsToOutput 列表中,并逐一打印出来:
    for (String output : resultsToOutput) {
    System.out.println(output);
    }

三、采坑心得
1.错误提示的优先级:
第三次改动后,代码格式中加入了很多错误输入及其提示信息,当一个输入中同时发生两个及以上的错误,我们必须考虑优先显示哪一类错误提示。
为了实现错误提示的优先级处理,我们需要在代码中根据优先级顺序来捕获和处理异常。首先,我们需要定义一系列特定的异常类来区分不同类型的错误。在处理每一行输入时,我们应该按照优先级顺序来捕获和处理异常:
(1)格式错误:首先处理输入格式错误。
(2)答案没有输入:其次处理答案没有输入的情况。
(3)题目编号唯一性验证:处理题目编号是否唯一。
(4)无效题目引用:处理题目编号在试卷中不存在的情况。
(5)学生学号唯一性验证:处理学生学号是否唯一。

2.学生信息的存储:
第三次改动后,需要录入学生信息并且查询它,我一开始使用动态数组进行存储,但发现数组无法直接保证数据的唯一性。如果试图存储具有唯一标识符(如学号)的学生信息,而这些标识符在数组中重复出现,那么就需要额外的逻辑来检查重复项,这增加了代码的复杂性。
替代方案:使用映射表

import java.util.HashMap;public class Main {private static Map<String, String> students = new HashMap<>();public static void main(String[] args) {// 添加学生信息students.put("12345", "张三");students.put("67890", "李四");// 查找学生信息String searchId = "12345";String foundName = students.get(searchId);if (foundName != null) {System.out.println("找到了学生: " + foundName);} else {System.out.println("未找到学生");}}
}

四、改进建议
1.模块化设计:
目前所有的逻辑都在main方法中处理,可以考虑将其拆分成更小的方法或者独立的类来提高可维护性和可测试性,比如:
(1)创建一个类来专门处理输入数据的解析。在这个类中,你可以定义多个静态方法,每个方法负责解析一种类型的输入数据。
(2)我们还可以创建一个类来负责验证输入数据的正确性。在这个类中,你可以定义多个静态方法,每个方法负责校验一个方面的数据。

2.异常处理
当前的程序中,异常处理部分比较宽泛,仅通过一个简单的catch块来捕获所有异常,并简单地记录错误信息。为了提高异常处理的精确度和可读性,可以根据具体的业务逻辑,可以定义一些特定的异常类来表示不同的错误情况。当输入格式不符合预期、试卷ID无效、题目ID无效和学生ID无效时抛出不同的异常类。然后,在处理输入时,针对不同的错误情况抛出不同的异常,并在catch块中分别处理。

3.输入验证:
输入验证是确保程序正确处理数据的关键步骤之一。通过增加更多的输入验证逻辑,可以提前发现潜在的问题,确保输入数据的有效性:
(1)题目编号唯一性验证:可以使用一个Set来存储已有的题目编号,每次添加新题目时检查是否已经存在。
(2)试卷题目分数组合验证:解析试卷时,需要确保题目分数组配合理,并且总分为100分。同时,还需要验证题目编号是否与题目列表中的编号匹配。
(3)学生学号唯一性验证:在解析学生信息时,需要确保学号唯一。可以使用一个Set来存储已有的学号,每次添加新学生时检查是否已经存在。
(4)答案数量一致性验证:在解析答案时,需要确保答案数量与试卷中的题目数量一致。如果不一致,则记录错误信息。

五、总结
通过本次三次作业的实践,我学到了以下几个方面:
1.数据结构的应用:
学会了使用映射表(如 HashMap)来存储和查询数据,特别是处理具有唯一标识符的数据时,映射表的优势明显。
使用集合(如 HashSet)来存储唯一数据,如题目编号和学生学号,确保数据的唯一性。
2.面向对象编程:
通过定义 TestPaper、Question、AnswerSheet 等类,掌握了面向对象的设计思想,增强了代码的可读性和可维护性。
定义了多个异常类来处理不同的错误情况,提高了程序的健壮性和异常处理的能力。
3.输入输出处理:
学会了如何解析不同格式的输入数据,并对其进行有效性验证。
使用 StringBuilder 等工具来格式化输出结果,确保输出的规范性和清晰度。
4.模块化设计:
通过将不同的功能封装成独立的方法或类,提高了代码的模块化程度,便于后续的维护和扩展。
尽管通过本次作业学到了很多,但在实际应用中还有许多需要进一步学习和研究的地方:
1.异常处理的精细化:
当前的异常处理相对粗略,可以通过定义更多具体的异常类来细化异常处理逻辑,从而更好地反映程序状态。
2.输入验证的全面性:
当前的输入验证主要集中在基本的格式和唯一性上,可以进一步增加更复杂的验证逻辑,如数据范围、格式正确性等。
3.性能优化:
在数据量较大的情况下,可以进一步优化算法和数据结构,提高程序的运行效率。
4.用户交互:
可以增加用户交互界面,使用户能够更直观地查看输入输出结果,提高用户体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/822564.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hello Web

Hello Web 兄弟们成了!!!我成了!!!在最近一段时间我基本没有发关于Web的博客,但是我一直在学习后端的知识和后端与前端交互的知识!!!从maven到mysql再到jdbc.mybatis,servlet,http,tomcat,终于,终于老子前端的代码可以把数据传到后端的数据库了!!!哈哈哈哈哈哈哈.我一路学习下来…

前三次大作业总结

一、前言 1. 题目一 1.1 知识点 1.1.1 类设计和封装:题目类:设计题号、题目内容和标准答案的基本属性,包含获取和设置方法,支持答案比对方法,用于判断答题是否正确。 试卷类:设计题目列表和题目数量两个属性,包含将题目存储到列表中的方法,能够按题号排序,以便在输出时…

云计算运维-SRE基础篇之安装VMware

一、首先简单总结计算机发展相关历史,详细总结服务器硬件和计算机分类相关知识。 计算机发展简史早期计算工具:从古至今,人类使用过多种计算工具,如算盘、计算尺等。这些工具为后来的机械计算器奠定了基础。 机械计算机时代(17世纪-19世纪):随着技术的发展,出现了更加复…

【Atcoder训练记录】AtCoder Beginner Contest 377

训练情况赛后反思 D题差一点点吧?可能不去乐跑就能写出来了 A题 我们发现 ABC 是字典序单调递增的,字符串先排序再判断是否为 ABC 即可。 #include <bits/stdc++.h> #define int long longusing namespace std;void solve(){string s; cin>>s;sort(s.begin(),s.e…

PbootCMS调用搜索页和标签页的关键词及数量

问题描述:PbootCMS调用搜索页和标签页的关键词及数量。 解决方法:搜索页 (search.html):获取关键词标签:{$get.keyword} 获取搜索结果数量:{page:rows}标签页 (tags.html):获取标签关键词:{$get.tag} 获取标签数量:{page:rows}扫码添加技术【解决问题】专注中小企业网站…

答题判题程序分析1

一、前言 对于这几周开始的Java答题判题程序的编写对我压力有点大,因为我对编程感觉总是慢半拍。虽然痛苦但也学习到了一些知识,过程艰辛但也有些许收获,让我对Java编程了解到了更多 这三次题目集的难度是逐渐向上攀升的,第一次题目集作业除了最后一题大作业都是入门级Java…

java-BLOG-1

1.前言 第一二个题目集除了最后一个题目以及第三个题目集的第一个题目都比较简单,只要按照题目要求,创建相应的类,题目比较简单一般只需要创建一个类和相应的一些属性、方法,按照输入输出的要求进行创建就行。前两个题目集只需要做对相应的输出就能做对,而第三个题目集重点…

使用opencvjs提取图片中的红色印章

首先看下效果:首先对于纯红色的印章提取,也就是通过提取红色 的像素然后得到印章的结果,然后通过在红色的图像中寻找圆圈检测来进行圈定印章的位置 源码位置:https://github.com/xxss0903/extractstamp第一步是提取红色内容function extractStampWithColorToOpencvMat(img,…

ELE-Electronics

Electronics是一本关于电子科学及其应用的国际同行评审开放获取期刊,同时也是一本跨学科多主题征稿期刊。@目录一、征稿简介二、重要信息三、服务简述四、投稿须知 一、征稿简介二、重要信息期刊官网:https://ais.cn/u/3eEJNv三、服务简述 CT/MRI图像中基于学习的韧带分割; 计…

题目集1~3总结与分析

一.前言 知识点考查和难度: 题目集一第一题 设计风扇Fan类考查了Java类的组成部分和具体的组成内容。 题目集一第二题 巩固了类和对象的使用,和其中的构造方法。 题目集一第三题 在第二题考查基础上添加了具体的方法。 题目集一第四题 进一步学习类的使用,做了简单的关联类…

idea 将文件夹改成source

首先可以 使用idea 右键选择 要更改的文件 make Directory as 选择 sources Root如果文件 不能选择, 可以 IDEA 直接点击 FILE 菜单 ,然后选择 Project Structure 然后 在 Modules 中,可以将文件夹 更改类型。