Java学习-答题判断程序1-3
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,Set
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.正则表达式使用:
学会使用正则表达式对用户输入进行验证,从而提高程序的健壮性。