Java学习-答题判断程序1-3

jianglingzzz / 2024-12-21 / 原文

1. 前言

(1) 答题判题程序-1

题目:设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。

知识点总结

1.基本语法与结构

学习和应用Java的基本语法,类的定义与实例化。

理解如何使用控制流(如循环和条件语句)。

2.数据封装与类设计

学习如何使用类封装数据和行为。

理解面向对象编程的基本原则,包括封装、继承及多态。

3.集合与数据结构

理解Java中集合框架(如ArrayList)的使用。

学会如何动态管理题目和答案的集合。

4.输入输出操作

熟悉Java中如何处理用户输入以及文件(标准输入/输出)作。学习如何格式化和输出数据。

5.字符串处理

学习如何对字符串进行操作,如拆分、拼接和去空格处理。

6.测试与调试

学习如何结构化代码以便进行单元测试和调试。理解如何输出和验证结果。

题量:本程序的设计适合处理任意数量的题目,但在输入数量时需要符合一定的格式。实际操作中的题量可以是1至N(N由用户输入)。

难度:初级到中级

(2) 答题判定程序-2

题目:要求输入题目信息、试卷信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。

新知识点

对象之间的关系:

设计多个类(如Question, TestPaper,和 AnswerSheet)并且理解它们之间的协作关系。第一题可能只涉及一个类或较少的类设计。

题量

(1)第二题支持任意数量的题目,通过用户输入的题目数量来决定实际处理的题目数。这种灵活性意味着可以很容易处理从1道题到N道题的情况。

(2)用户可以输入多个问题和答案,而且题目的输入顺序不必遵循编号顺序,增加了对输入格式的要求。

难度:中级到高级

(3) 答题判断程序-3

题目:要求输入题目信息、试卷信息、答题信息、学生信息、删除题目信息,根据输入题目信息中的标准答案判断答题的结果。

新知识点:

(1)正则表达式的使用:使用正则表达式来解析用户输入,检测输入格式的有效性

(2)错误处理机制:增加了对格式错误的处理,能够提示用户输入错误,增强了程序的健壮性

题量:
(1)允许用户输入任意数量的题目、试卷、学生和答案,程序的适应性和灵活性比前两题更高。
(2)用户可以随意调整输入的顺序,这直接影响到对题目的解析和输出结果的顺序,使得整合答案的过程更加复杂。

难度:中级到高级

2.设计与分析

(1) 答题判题程序-1

类图:


类的分析:

1. Question类:

属性:number:题号content:题目内容standardAnswer:标准答案

方法:构造函数:初始化题号、内容和标准答案,并去除多余空格

判断用户的答案是否与标准答案匹配,不区分大小写

TestPaper类:

属性:questions:存储所有题目的列表。

方法:添加一道题目。根据题号获取题目。返回所有题目列表。

AnswerSheet类:

属性:testPaper:关联的试卷对象。answers:存储用户的答案列表。evaluationResults:存储每道题目的评估结果(正确与否)。

方法:添加用户的答案。评估用户的答案,将每道题的正确性存储在 evaluationResults 列表中。 输出题目内容、用户答案及其评估结果。

主程序(Main类):

输入处理:从控制台读取题目数量。使用循环读取每道题的详细信息,包括题号、题目内容和标准答案,通过字符串分割来提取。

答案输入:读取用户答案,直到输入"end",通过split分割并逐个添加到 AnswerSheet 对象中。

评估和输出:调用 evaluateAnswers() 方法,评估用户的答案。调用 printResults() 方法输出结果,包括题目内容和用户的回答。

(2) 答题判题程序-2

类图:


类的分析:

Question类:

属性:number:题号content:题目内容standardAnswer:标准答案

方法:构造函数:初始化题号、内容和标准答案,并去除多余空格。checkAnswer(Stringanswer):判断用户的答案是否与标准答案匹配。

TestPaper类:

属性:id:试卷唯一标识questions:存储题号及其分值的映射(使用Map结构)totalScore:试卷的总分questionOrder:题号的顺序列表(使用 List 结构)

方法:addQuestion(intnumber,intscore):添加一道题目及其分值,更新总分。

getTotalScore():获取试卷总分。

getId():获取试卷ID。

getQuestionOrder():返回题号的顺序。

getQuestionScore(intnumber):根据题号获取分值,未找到返回0。

AnswerSheet类:

属性:testPaper:关联的试卷对象。answers:存储用户的答案列表。results:存储每道题的评估结果(是否正确)。scores:存储每道题的得分。

方法:

addAnswer(Stringanswer):添加用户的答案。

evaluateAnswers(Map<Integer,Question>questions):评估用户的答案,将每道题的正确性和得分存储在 results 和 scores 列表中。

printResults(Map<Integer,Question>questions):输出每道题的内容、用户的答案及评估结果,最后输出总得分。

ExamProcessor****类:

属性:questions:存储所有题目的映射(使用 Map 结构)。testPapers:存储试卷的映射。answerSheets:存储所有答案表的列表。alertPrintedTestPapers:存储需要警告的试卷ID。testPaperMismatch:标识是否存在试卷不匹配的情况。

方法:processInput(Scannerinput):处理输入,解析题目、试卷、答案等,并进行错误检查。printResults():打印警告(如果有)并输出每个答案表的结果。

主程序(Main类):

输入处理:使用Scanner读取输入,然后调用ExamProcessor处理用户输入。

评估和输出:processInput() 方法负责解析输入。

printResults() 方法输出结果,包括警告信息和各个成绩单的详细信息。

(3) 答题判断程序-3

类图:


类的分析

Question类

属性:number:题号content:题目内容standardAnswer:标准答案

方法:

构造函数: Question(intnumber,Stringcontent,StringstandardAnswer):初始化题号、内容和标准答案,并去除多余空格。checkAnswer(Stringanswer):判断用户的答案是否与标准答案匹配,返回布尔值。

Student类

属性🆔学生的唯一标识符(ID)name:学生的姓名

方法:

构造函数: Student(Stringid,Stringname):初始化学生ID和姓名,并去除多余空格。

getId():返回学生ID。

getName():返回学生姓名。

toString():返回学生信息的字符串表示,便于输出和调试。

TestPaper类

属性🆔试卷唯一标识

questions:存储题号及其分值的映射,使用 Map<Integer,Integer> 结构。

totalScore:试卷的总分。

questionOrder:题号的顺序列表,使用 List 结构。

方法:

addQuestion(intnumber,intscore):添加一道题目及其分值,更新总分。

getTotalScore():返回试卷的总分。

getId():返回试卷ID。

getQuestionOrder():返回题号的顺序列表。

getQuestionScore(intnumber):根据题号获取对应的分值,若未找到则返回0。

AnswerSheet类

属性:

testPaper:关联的试卷对象。

answers:存储用户的答案列表,使用 List 结构。

results:存储每道题的评估结果(是否正确),使用List 结构。

scores:存储每道题的得分,使用 List 结构。

方法:

addAnswer(Stringanswer):添加用户的答案,将答案去除多余空格。

evaluateAnswers(Map<Integer,Question>questions,SetdeletedQuestions):根据题目及删除的题目评估用户的答案,将每道题的正确性和得分存储在 results 和 scores 列表中。

printResults(Map<Integer,Question>questions,StringstudentId):输出每道题的内容、用户的答案及评估结果,最后输出总得分。

ExamProcessor类

属性:

questions:存储所有题目的映射,使用 Map<Integer,Question> 结构。

testPapers:存储试卷的映射,使用 Map<String,TestPaper> 结构。

answerSheets:存储所有答案表的列表,使用 List 结构。

alertPrintedTestPapers:存储需要警告的试卷ID,使用 Set 结构。

testPaperMismatch:标识是否存在试卷不匹配的情况,使用布尔值。

· 方法:

processInput(Scannerinput):处理输入,解析题目、试卷、学生和答案,并进行错误检查。

processQuestion(Stringline):处理题目信息的输入。

processTestPaper(Stringline):处理试卷信息的输入。

processStudents(Stringline):处理学生信息的输入。

processAnswerSheet(Stringline):处理答案信息的输入。

processDeleteQuestion(Stringline):处理删除题目信息的输入。

printResults():打印警告(如果有)并输出每个答案表的结果。

主程序(Main类)

· 输入处理:使用 Scanner 读取输入,直到读取到"end"。

· 评估和输出:调用 ExamProcessor 的 processInput() 方法处理用户输入,最后输出结果,包括警告信息和各个成绩单的详细信息。

3.踩坑心得

1.关于类的设计以及函数的运用

如果说C语言是面向过程的语言,那么Java就是面向对象的语言。创建类以及对函数的运用是至关重要的。

本次题目的类分为操作类和对象类。

对象类:

设计Question、Student、Tsetpaper类用来储存封装对象信息。如下图:

类中的属性通常用private访问修饰符进行封装,通过公共的getter和setter方法访问和修改。主要功能是通过方法来访问和修改对象里的信息。

操作类:

设计AnswerSheet、ExamProcessor的操作类来进行操作效率的提升。如下图:


AnswerSheet和ExamProcessor 类通过组合和依赖关系与 TestPaper和Question类相互关联。通过这种设计,代码能够灵活地管理考试信息,并处理学生的答案,无论是评估还是输出结果。这种清晰的类关系设计使得代码易于维护和扩展。

函数的运用:

List:被广泛用于要保持顺序和可重复元素的场合,尤其是在处理答案、结果和问题顺序时。

Map:用于快速查找和存储唯一键与值的关系,方便在实践中检索问题、试卷和学生信息。

Set:用于保持唯一性,确保在评估和处理数据时不会重复。

这种组合使用使得程序结构明晰,数据存取高效,符合良好的编程实践

如果不对类的创建和函数的运用加以合理的使用,那么很大程度上对代码的可读性和利用性大打折扣。Java语言是面对对象的语言,有很强的迭代性,如果对各个对象的信息不加以封装,很容易造成信息的冗杂混乱。

2.输出顺序的注重:

输出的顺序应该是:

(1) 判断输入的试卷的总分是否是100分,如若不是,则输出:alert:fullscoreoftestpaperisnot100points。

(2) 判断答卷是否有对应的试卷,如果没有,则输出:Thetestpapernumberdoesnotexist。如果存在则输出每道题的内容以及对应的结果。如果输入的答案信息少于试卷的题目数量,缺失答案的题目输出"answerisnull" 。如果题目被删除,则输出0

(3) 输出学号+""+姓名+": "+题目得分+""+....+题目得分+"~"+总分

在输出每张答卷时及情况时要主要顺序:

错误案例:

代码中只是简单地设置了标志符,判断是否存在答卷是否有对应地试卷,并没有考虑到输出每张答卷时要注意顺序,造成输出结果的错误和混乱。

输入样例:

#N:3#Q:3+2=#A:5

#N:2#Q:2+2=#A:4

#T:13-72-6

#S:3#A:5#A:22

#N:1#Q:1+1=#A:2

#T:22-51-33-2

#S:2#A:5#A:4

End

正确输出结果:

alert:full score of test paper1 is not 100 points

alert:full score of test paper2 is not 100 points

The test paper number does not exist

2+2=5false

1+1=4false

Answer is null

000~0

错误输出结果:

alert:full score of test paper1 is not 100 points

alert:full score of test paper2 is not 100 points

2+2=5false

1+1=4false

Answer is null

000~0

The test paper number does not exist

所以当写程序时,要着重注意输出的顺序。

3.正则表达式的运用

当题目出现判断输入是否合法时,可以使用正则表达式来进行判别。例:

如果写方法去判别,会显得繁琐。如:

使用正则表达式:

加以使用boolean来返回结果便可以进行判别输入是否合法。

4.归零返回的出现

Pta出现非零返回的现象,如图:

对数据的输入处理有问题

如:第二行输入两个数据,但却错误处理



上述中第二行的输入为两个数据,却进行错误地分割。

​ 如:输入错误

​ 我将第一行的标准答案改为了“null”,但是处理时会将其变为int类型的整数导致错误。

​ 解决办法:(1)确保你的代码针对可能抛出的异常进行处理。使用try-catch结构,可以捕获各种运行时异常并输出相关信息,帮助定位问题。

​ (2)对代码进行分块式检测,找出产生错误的区域进行修改

4.改进建议

(1)代码复用和方法分解

提取公共代码:多处使用类似的解析逻辑(如分割字符串),可以将这些逻辑提取成公共方法,以提高代码的清晰度和可复用性。

方法单一责任原则:确保每个方法只负责一种功能。比如,processAnswerSheet 方法可以分拆成多个小方法来处理不同的逻辑。

(2)结果输出的格式

改进输出格式:在最终输出结果时,可以考虑将格式化逻辑分离出来,这能使输出结果更具可读性并方便后续调试。

使用StringBuilder:在打印多行数据时,使用 StringBuilder 可以提高性能,特别是在循环中拼接字符串时。

(3)用户交互

用户友好的提示:对于用户输入过程中,适当添加提示和说明,以帮助用户更好地理解需要输入的格式。

(4)数据验证

输入数据的合法性检查:在各种输入的处理方法中,增加对数据合法性的验证(如分数是否为负,问题编号是否有效等)。

删除操作的校验:在删除题号时,建议检查是否存在该题号。

5.总结

此次项目从设计到实现的过程,不仅让我加深了对Java编程语言的理解,还增强了我在面向对象编程和数据结构方面的能力。以下是我对这次经历的补充总结:

1. 面向对象编程的重要性

通过将程序设计为多个类,我清晰地理解了如何使用面向对象的原则来组织和封装数据。从 Question、Student 到 TestPaper 以及 AnswerSheet 类的设计,使我体会到如何将现实世界的元素转化为编程中的对象,保持程序结构的清晰和可维护性。

2.有效的数据结构选择

在项目实现中,我尝试使用 List、Map 和 Set 等数据结构,各自在不同场景中发挥其优势。比如:

使用 List 来维护题目的顺序和用户的答案,使得操作更为直观。

使用 Map 来实现题号与分数之间的映射,以支持快速查询。

使用 Set 来避免重复问题的存储,保障数据的一致性和有效性。

这种合理的数据结构使用提高了程序的性能,使其在处理大规模数据时表现更加流畅。

3.输入输出的处理

学习到如何灵活处理用户输入和控制输出格式,让我意识到用户体验在程序设计中的重要性。通过良好的输入提示和格式化输出,程序不仅能有效地获取数据,还能清楚易懂地反馈结果。

4.错误处理与验证

在设计错误处理机制时,我意识到了在整个应用程序中保持健壮性的重要性。在处理输入数据时,对其合法性和有效性进行验证,有助于避免潜在的运行错误,提高了系统的稳定性。

5.正则表达式使用

学会使用正则表达式对用户输入进行验证,从而提高程序的健壮性。