题目集1~3的总结性Blog
一、前言
相关知识点:
1、第一次题目集主要是对java的类的设计以及相关的方法的使用,包括数组的使用方法,类和对象的使用等进行考察。
2、第二次题目集则是对第一次题目集的一次强化以及补充,要求掌握排序以及查找相关方法的使用,以及对于类与对象的概念进行了强调。
3、第三次题目集对类的封装以及日期类的基本使用进行了考察。每一次的题目的完成都比上一次更加的困难,知识点由浅入深慢慢的提升我们的编程思维。
题量:
三次题目集的题目量分别为5+4+3,第一次对基本的类与方法的使用做出了要求,之后每次都在上一次增加难度循序渐进。
难度:
三次题目集的难度是直线上升的,尤其体现在每次题目及最后的答题判断程序的设计上,后面两次每一次都建立在上一次的基础上,但是在做出修改时还是很困难。
二、设计与分析
1、答题判断程序-1
根据题意设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
题目中的输入分为三个部分题目数量、题目内容以及答题信息,最后以输入的end结尾,对题目进行分析,根据输入的格式则是首先根据输入的“#”来进行分割再根据“:”
来进行分割后将题目以及标准答案的内容放入数组中,之后在答案部分再以“#A”为起始,根据“ ”来进行分割。然后再将判断答案是否与标准答案相同,之后再进行输出。
题目要求将信息分为三个类,1、题目类(用于封装单个题目的信息)2、试卷类(用于封装整套题目的信息)3、答卷类(用于封装答题信息)。由此设计出
以上三个类以及调用他们的Main函数。
public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int questionCount = Integer.parseInt(scanner.nextLine().trim()); Paper paper = new Paper(); for (int i = 0; i < questionCount; i++) { String line = scanner.nextLine().trim(); String[] parts = line.split("#"); // 使用 # 进行分割 int number = Integer.parseInt(parts[1].split(":")[1].trim()); String content = parts[2].split(":")[1].trim(); // 题目内容 String standardAnswer = parts[3].split(":")[1].trim(); // 标准答案 paper.addQuestion(new Question(number, content, standardAnswer)); } AnswerSheet answerSheet = new AnswerSheet(paper); String answerLine; while (!(answerLine = scanner.nextLine().trim()).equals("end")) { String[] answerParts = answerLine.split(" "); // 根据空格分割 for (String answer : answerParts) { if (answer.startsWith("#A:")) { answerSheet.addAnswer(answer.substring(3).trim()); // 移除 #A: } } } answerSheet.checkAnswers(); answerSheet.printResults(); } }
其中AnsewerSheet类中包含了最后答卷的输出,再Main中调用answerSheet.printResult();来将结果显示出来。
SourceMonitor分析如下:
2、答题判断程序-2
在答题判断程序-1上做出了修改,以1为基础新增了试卷信息的输入且输入信息的顺序被打乱,因此1中的判断程序必须重新修改以确保正确的输出
且在输入不正确时多了更多的报错,现阶段输入信息分为三类
1、题目信息
一行为一道题,可输入多行数据(多道题)。
格式:"#N:"+题目编号+" "+"#Q:"+题目内容+" "#A:"+标准答案
2、试卷信息
一行为一张试卷,可输入多行数据(多张卷)。
格式:"#T:"+试卷号+" "+题目编号+"-"+题目分值
3、答卷信息
答卷信息按行输入,每一行为一张答卷的答案,每组答案包含某个试卷信息中的题目的解题答案,答案的顺序与试卷信息中的题目顺序相对应。
格式:"#S:"+试卷号+" "+"#A:"+答案内容
根据输入时以"#N"、"#T"、"#S"开头来判断输入的是以上三种信息的哪一种,并将其存入相应的数组中
实现代码:
if (input.startsWith("#N:")) { String[] parts = input.split(" "); int number = Integer.parseInt(parts[0].substring(3)); String content = parts[1].substring(3); String answer = parts[2].substring(3); questions.put(number, new Question(number, content, answer)); } else if (input.startsWith("#S:")) { String[] parts = input.split(" "); int testPaperNumber = Integer.parseInt(parts[0].substring(3)); List<String> answers = new ArrayList<>(); for (int i = 1; i < parts.length; i++) { answers.add(parts[i].substring(3)); } answerSheets.add(new answerPaperSheet(testPaperNumber, answers)); } else if (input.startsWith("#T:")) { String[] parts = input.split(" "); int testPaperNumber = Integer.parseInt(parts[0].substring(3)); TestPaper testPaper = new TestPaper(testPaperNumber); for (int i = 1; i < parts.length; i++) { String[] questionScore = parts[i].split("-"); int questionNumber = Integer.parseInt(questionScore[0]); int score = Integer.parseInt(questionScore[1]); testPaper.addQuestion(questionNumber, score); } testPapers.put(testPaperNumber, testPaper); if (testPaper.TotalScore() != 100) { addPapers.add(testPaperNumber); } }
在答题判断程序-1的基础上三个类也做出了相应的改变,以下是类图
延续了答题判断程序-1的三个类并对其做出了更改在此次的程序中加入了哈希表的应用。由于在完成时遇到了许多问题所以将许多东西都已到了Main中
因此Main函数的代码过多此处则选择性的选出一部分。以下为当输入错误时以及相关的错误时以及各种输出的时候所需要的代码
for (int paperNumber : addPapers) { System.out.println("alert: full score of test paper" + paperNumber + " is not 100 points"); } for (answerPaperSheet sheet : answerSheets) { if (!testPapers.containsKey(sheet.testPaperNumber)) { System.out.println("The test paper number does not exist"); continue; } TestPaper paper = testPapers.get(sheet.testPaperNumber); List<String> results = new ArrayList<>(); List<Integer> scores = new ArrayList<>(); int totalScore = 0; int allAnswer = 0; for (int questionNumber : paper.questionScores.keySet()) { int score = paper.questionScores.get(questionNumber); String giveAnswer = allAnswer < sheet.answers.size() ? sheet.answers.get(allAnswer) : null; Question question = questions.get(questionNumber); if (question != null) { if (giveAnswer == null) { results.add("answer is null"); scores.add(0); } else { boolean right = question.answer.equals(giveAnswer); results.add(question.content + "~" + giveAnswer + "~" + (right ? "true" : "false")); scores.add(right ? score : 0); } } else { results.add("answer is null"); scores.add(0); } totalScore += scores.get(scores.size() - 1); allAnswer++; } for (String result : results) { System.out.println(result); } System.out.println(String.join(" ", scores.stream().map(String::valueOf).toArray(String[]::new)) + "~" + totalScore); }
用于判断试卷满分是否为100分以及输入的答案是否与标准答案相同,以及输入的试卷号是否存在等。
SourceMonitor分析如下:
3、答题判断程序-3
与前两次的程序相比第三次的答题判断程序加入了更多的输入信息前两次的输入都为三种信息在本次的答题判断程序中则变为了五种
新增了学生信息以及删除题目信息以下为新增两种信息的格式
1、学生信息
学生信息只输入一行,一行中包括所有学生的信息,每个学生的信息包括学号和姓名,格式如下。
格式:"#X:"+学号+" "+姓名+"-"+学号+" "+姓名....+"-"+学号+" "+姓名
2、删除题目信息
删除题目信息为独行输入,每一行为一条删除信息,多条删除信息可分多行输入。该信息用于删除一道题目信息,题目被删除之后,引用该题目的试卷依然有效,但被删除的题目将以0分计,同时在输出答案时,题目内容与答案改为一条失效提示,例如:”the question 2 invalid~0”
格式:"#D:N-"+题目号
错误提示也新增了被删除的题目提示信息当某题目被试卷引用,同时被删除时,答案中输出提示信息以及题目引用错误提示信息试卷错误地引用了一道不存在题号的试题,在输出学生答案时,提示”non-existent question~”加答案。因此在需要增加的判断函数也增加了,以及答题判断程序-2中的三个类也必须做出相对应的改变才行
以下为更改后的类图:
在AnswerPaperSheet类中加入了studentid以及AnswerPaperSheet()函数中加入了String studentid以便后续对学生信息的处理
在Main函数中则根据输入的信息的开头以"#N:"、"#T:"、"#X:"、"#S:"、"#D:N-"中的某一个开头来进行判断输入的为何种信息。
并进行对应的报错。
if (input.startsWith("#N:")) { String[] parts = input.split(" "); if (parts.length != 3 || !parts[0].startsWith("#N:") || !parts[1].startsWith("#Q:") || !parts[2].startsWith("#A:")) { System.out.println("wrong format:" + input); continue; } try { int number = Integer.parseInt(parts[0].substring(3)); String content = parts[1].substring(3); String answer = parts[2].substring(3); questions.put(number, new Question(number, content, answer)); } catch (Exception e) { System.out.println("wrong format:" + input); } } else if (input.startsWith("#T:")) { String[] parts = input.split(" "); if (parts.length < 2 || !parts[0].startsWith("#T:")) { System.out.println("wrong format:" + input); continue; } try { int testPaperNumber = Integer.parseInt(parts[0].substring(3)); TestPaper testPaper = new TestPaper(testPaperNumber); for (int i = 1; i < parts.length; i++) { String[] questionScore = parts[i].split("-"); int questionNumber = Integer.parseInt(questionScore[0]); int score = Integer.parseInt(questionScore[1]); testPaper.addQuestion(questionNumber, score); } testPapers.put(testPaperNumber, testPaper); if (testPaper.totalScore() != 100) { invalidTestPapers.add(testPaperNumber); } } catch (Exception e) { System.out.println("wrong format:" + input); } } else if (input.startsWith("#X:")) { String[] parts = input.substring(3).split("-"); for (String part : parts) { String[] studentInfo = part.split(" "); if (studentInfo.length == 2) { students.put(studentInfo[0], studentInfo[1]); } else { System.out.println("wrong format:" + input); break; } } } else if (input.startsWith("#S:")) { String[] parts = input.split(" "); if (parts.length < 3 || !parts[0].startsWith("#S:") || !students.containsKey(parts[1])) { System.out.println("wrong format:" + input); continue; } try { int testPaperNumber = Integer.parseInt(parts[0].substring(3)); String studentId = parts[1]; List<String> answers = new ArrayList<>(); for (int i = 2; i < parts.length; i++) { String[] answerParts = parts[i].split("-"); if (answerParts.length == 2) { answers.add(answerParts[1].trim()); } else { System.out.println("wrong format:" + input); break; } } answerSheets.add(new AnswerPaperSheet(testPaperNumber, studentId, answers)); } catch (Exception e) { System.out.println("wrong format:" + input); } } else if (input.startsWith("#D:N-")) { try { int questionNumber = Integer.parseInt(input.substring(5)); deletedQuestions.add(questionNumber); } catch (Exception e) { System.out.println("wrong format:" + input); } } else { System.out.println("wrong format:" + input); } }
Main函数的主体与答题判断程序-2的大致相同,但是新增了更多的报错以及输出。
SourceMonitor分析如下:
三、踩坑心得
1、首先便是我已经不知道第多少次忘记的在PTA中只能用Main来写主方法,在IDEA上还能好好运行一到PTA上就出现了以下报错,
将主函数名改为Main即可。
2、没有注意到输出的格式随意编写输出导致输出的格式不符合,导致测试点全错。
更改后:
3.输出顺序的注重:
输出的顺序应该是:
(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
所以当写程序时,要着重注意输出的顺序。
四、改进建议
1. 异常处理
在解析输入时添加异常处理,确保程序在遇到无效输入时能够优雅地处理,而不是直接崩溃。例如,可以捕获 NumberFormatException。
2. 输入解析方法
将输入解析部分提取成单独的方法,增强代码的可读性和可维护性。
3. 改进 printResults 方法
在打印结果时,可以使用 StringBuilder 来构建输出,减少多次调用 System.out.print 带来的性能损耗。
4. 使用常量
对于常量字符串(如 "#A:"),可以考虑使用常量字段,增加代码的可读性和维护性。
5. 主程序逻辑简化
主程序逻辑可以分成多个小函数,减少 main 方法的复杂度。
6. 代码注释
适当添加注释,尤其是在复杂逻辑的地方,能够帮助未来的维护者更快理解代码。
五、总结
这三次Java作业的主要任务是实现一个简单的问答系统,包括题目管理、答案录入以及结果评估功能。系统通过命令行界面与用户交互,用户可以输入题目和标准答案,然后录入自己的答案并获取结果。本次作业加深了对面向对象设计的理解,特别是如何通过类与对象封装数据和行为。本次作业特别强调了相关类的书写而且用过本次作业学习了正则表达式的用法,对以后代码的书写提供了便利。还学习到了如何通过重构提升代码的质量,注重代码的可读性和可维护性。
经过这三次的java大作业我对我自己水平的不足有了深刻的认识,在许多地方都一知半解,导致每次都没法完整的完成作业,在之后我会花费更多的时间去练习java程序的编写。