-
前言
-
第一題知識點
1.基礎Java語法與資料型別
int: 基本資料型別,用於儲存整數,例如 numOfQuestions 是題目數量。
String: 物件型別,用於處理字串資料。所有輸入和輸出的資料處理都涉及到字串處理,例如 line 表示從使用者輸入讀取的一行資料。
2. 輸入輸出
Scanner類:
Scanner scanner = new Scanner(System.in); 用於讀取使用者輸入。System.in 代表標準輸入(通常是控制檯)。
scanner.nextLine() 讀取整行輸入資料,通常以 \n 作為結束符。
System.out.println():
用於列印輸出。該程式用來顯示題目內容和使用者的答案,以及最終的判題結果。
3. 集合框架
Map介面與HashMap類:
Map<Integer, String> 用來儲存鍵值對 (key-value),此處的 Integer 是題號,String 是題目。
HashMap 是 Map 的實現類,提供了 put() 方法來插入資料、get() 方法來獲取資料。
questionMap.put(questionNumber, questionContent) 將題號和題目內容存入 questionMap。
List介面與ArrayList類:
List用於儲存順序資料,如使用者的答案和判題結果。
ArrayList 是 List 的實現類,可以動態調整大小。
userAnswers.add(ans.substring(3)) 用來去掉 #A: 標記並將使用者答案存入 userAnswers 列表。
4. 字串操作
String.indexOf(String str):
返回指定子字串 str 在字串中首次出現的索引。如果不存在則返回 -1。
用於定位 #N:, #Q:, #A: 的位置,例如 line.indexOf("#N:") + 3 用於獲取題號的開始位置。
String.substring(int beginIndex, int endIndex):
返回從 beginIndex 到 endIndex 之間的子字串(不包含 endIndex 字元)。
用來提取題號、題目和正確**。
String.trim():
去除字串兩端的空白字元。
常用於清理使用者輸入資料,如 scanner.nextLine().trim()。
5. 迴圈與條件判斷
for 迴圈:
用於迴圈處理題目的讀取和輸出。
for (int i = 0; i < numOfQuestions; i++) 遍歷題目輸入。
while 迴圈:
用於逐行讀取使用者的答題資訊,直到輸入 end 為止。
while (!answerLine.equals("end")) 檢查使用者輸入是否為 end。
if-else 條件語句:
用來判斷使用者答案是否正確。
if (answerMap.get(questionNumber).equals(userAnswer)) 判斷使用者答案和正確答案是否相等。
6. 排序
Collections.sort(Listlist):
該方法用於對列表進行排序。程式對 questionMap 的鍵列表進行排序,以確保按題號順序輸出。
Collections.sort(sortedKeys) 將題號列表按從小到大的順序排序。
7. Java中的錯誤處理
程式中使用了 Integer.parseInt() 方法來將字串轉換為整數。如果使用者輸入的題號不是有效的整數,這裡可能會丟擲 NumberFormatException 異常。雖然程式碼裡沒有專門的異常處理部分,但在實際應用中,可以考慮使用 try-catch 塊來捕獲和處理這些異常,確保程式的健壯性。
8. 資料讀取和解析
程式碼展示瞭如何處理格式化輸入。比如: #N:1#Q:What is 2+2?#A:4,這種格式化的輸入需要使用字串操作技巧來提取不同部分。
這種字串解析技巧是處理文字資料時非常常見的程式設計模式。
9. ArrayList的用法
add(element): 將元素新增到列表末尾。
get(index): 獲取指定索引處的元素。
size(): 獲取列表的大小。 -
第二題知識點
- 類與物件
類的定義:Question、TestPaper、AnswerSheet三個類分別封裝了題目、試卷和答題卡的資料和行為。
構造方法:每個類都定義了構造方法(Question(int id, String content, String answer)等),用於物件的初始化。構造方法在建立物件時自動呼叫,確保物件的初始狀態正確。
屬性的封裝:每個類使用公有屬性來儲存資料。為了更好的設計,屬性一般設定為private並透過getter和setter訪問,但此處屬性為public用於簡化示例程式碼。 - 集合框架
Map介面及其實現類:HashMap用於儲存題目,LinkedHashMap用於儲存試卷的題目-分數對映。
HashMap實現基於雜湊表,提供O(1)的查詢效率。題目列表(questionMap)透過HashMap按題目ID快速查詢。
LinkedHashMap在TestPaper類中用於保持題目新增的順序。LinkedHashMap保留插入順序,便於控制輸出順序。
List介面及其實現類:ArrayList用於儲存考生的**(answers)。
ArrayList是一種可動態擴充套件的陣列,適合儲存有序的、可變數量的物件,如考生的答題順序。 - 字串處理
split方法:利用String類的split方法解析輸入字串,根據不同的識別符號提取資料。
substring方法:substring用於擷取字串中的特定部分(如#T:123獲取試卷ID 123)。
字串比較:利用String.equals方法來檢查考生**與正確答案是否匹配。 - 控制結構
迴圈結構:for和while迴圈用於遍歷集合和讀取輸入。
for-each迴圈用於遍歷集合元素,如for (AnswerSheet sheet : answerSheets)。
條件判斷:if語句用於檢查輸入型別,驗證答題的正確性等。
跳出迴圈:break用於終止while迴圈,當使用者輸入“end”時退出。 - 標準輸入和輸出
Scanner類:Scanner用於從控制檯讀取輸入,結合nextLine()方法逐行讀取資料。
標準輸出:利用System.out.println輸出處理結果、分數、答題正確性提示等資訊。
-
第三題知識點
1. 類的設計
Question類:題目類,包含id(題目ID)、content(題目內容)和answer(題目正確答案)三個屬性。透過構造方法Question(int id, String content, String answer)來初始化一個Question物件。
TestPaper類:試卷類,用來管理一個試卷上的題目及對應分數,包含:
id:試卷的ID。
questions:一個Map<Integer, Integer>,用來儲存題目ID及其對應的分數。這裡Map的鍵值對結構很適合題目與分數的繫結關係。
totalScore:記錄試卷的總分,透過addQuestion(int qId, int score)方法將題目新增到試卷並更新總分。
checkFullScore()方法:檢查試卷的滿分是否是100分。如果不是滿分100分,後續會輸出警告資訊。
AnswerSheet類:答卷類,用來管理學生的答卷資訊,包含:
testPaperId:答卷所屬試卷的ID。
studentId:學生的ID。
answers:儲存每道題目對應的學生答案。方法addAnswer(String answer)將學生的答案新增到answers列表中。
Student類:學生類,記錄學生的基本資訊。包含學生的id(學號)和name(姓名),用於標識每個學生。
Main類:主類,透過main方法執行整個程式的控制邏輯,包括從輸入獲取資料、處理各種資料型別(題目、試卷、答卷等),並完成最終的答卷評分和輸出。
2. 資料結構的使用
Map介面(HashMap和LinkedHashMap):
questionMap:用於儲存題目,鍵是題目ID,值是Question物件。
testPaperMap:用於儲存試卷,鍵是試卷ID,值是TestPaper物件。
studentMap:用於儲存學生,鍵是學生ID,值是Student物件。
LinkedHashMap用於TestPaper類中的questions欄位,因為它可以保持插入的順序,確保題目在答卷中的順序正確。
List介面(ArrayList):用於儲存按順序排列的資料:
answerSheets:儲存所有學生的答卷AnswerSheet物件。
answers:AnswerSheet類中儲存學生每個題目的答案。
Set介面(HashSet):deletedQuestions用於儲存已刪除的題目ID。HashSet的查詢效率較高,這樣在驗證某個題目是否被刪除時會更快速。
3. 輸入輸出和資料解析
輸入處理:
使用Scanner從標準輸入逐行讀取資料。sc.nextLine()讀取一行字串,trim()去除兩端的空白,input.startsWith("#N:")檢查輸入字首以確定行的型別。
透過字串方法split()解析不同輸入模式:
"#N:"開頭的行用於定義題目,解析出題目ID、內容、答案後,將題目存入questionMap。
"#T:"開頭的行用於定義試卷,將題目和分數解析後新增到試卷TestPaper物件中。
"#S:"開頭的行用於定義答卷,解析答卷的試卷ID、學生ID、學生答案。
"#X:"開頭的行用於定義學生,將學生ID和姓名解析後存入studentMap。
"#D:N-"開頭的行表示刪除某個題目,記錄在deletedQuestions中。 -
這幾次的題量稍大,如果不留足充裕的時間,很難答完所有題目並透過所有測試點,這三次的題目難度隨著每一次更迭,難度在逐漸增大,第一次比較簡單,能夠很快完成,第二次難度稍微增大需要投入更多的時間和精力去完成,第三次難度較大,需要花費很多時間和精力去完成。
-
第一題設計分析
1.題目定義了清晰的輸入格式,分為三部分:
題目數量:代表後續題目數的整數,最高位不能為0(也就是說數字不應以0開頭)。
題目內容:
格式為 #N:<題號> #Q:<題目內容> #A:<標準答案>。
題號與題目輸入順序無關,意味著我們可能需要將題號與題目內容、答案進行關聯儲存,之後按題號順序排序輸出。
答題資訊:
答題資訊按行輸入,以 #A:<答案內容> 格式儲存。
每行的答題資料對應每道題目,順序與題號對應(題號按升序排列後答案與題目內容的順序一致)。
end 標記答題資訊輸入結束。
2.輸出結構分析
程式的輸出分為三部分:
題目數量:直接輸出已讀取的題目數量。
題目內容及使用者答案:輸出題目內容和使用者答案(格式 題目內容~答案),按題號從小到大的順序。
判題資訊:根據使用者的答案判斷正誤,並輸出 true 或 false(順序與輸入答題資訊的順序一致)。
3.程式設計與資料結構
根據題目的要求,我們可以設計以下資料結構來儲存題目和答案資訊:
題目資訊儲存結構
使用 Map<Integer, String> 來儲存題目編號與題目內容,便於透過題號來儲存和查詢。
使用 Map<Integer, String> 來儲存題目編號與標準答案。
使用者答案與判題資訊儲存
使用 List儲存使用者的答題資訊,逐條新增使用者的答案。
使用 List或 List 儲存判題結果,最終輸出 true 或 false。
4.具體步驟設計
以下是按題目要求拆解的詳細程式流程:
(1. 讀取輸入部分
讀取題目數量:讀取並解析第一行,獲取題目數量 numOfQuestions。
讀取題目內容:
迴圈讀取接下來的 numOfQuestions 行,每行包含題號、題目內容和標準答案。
使用字串分割、索引定位(#N:, #Q:, #A:)提取題號、題目內容和標準答案。
將題號與題目內容、標準答案分別存入 questionMap 和 answerMap 中。
讀取使用者答題資訊:
使用 while 迴圈讀取答題資訊行,直到 end。
每行將 #A:<答案內容> 格式的資料提取成單獨答案,去掉字首 #A:。
將使用者的答案按順序存入 userAnswers 列表。
(2. 處理與輸出部分
輸出題目數量:直接輸出 numOfQuestions。
輸出題目內容及使用者答案:
按題號從小到大排序 questionMap 的鍵。
根據排序後的題號順序逐一輸出題目內容和使用者的答案,格式為 題目內容~使用者答案。
判題:
遍歷題號列表,逐一將使用者的答案和標準答案比對,若相等則判為 true,否則判為 false。
將判題結果存入 results 列表,最終輸出結果。 -
第一題改進建議
- 題目資訊的輸入與解析
點選檢視程式碼
Map<Integer, String> questionMap = new HashMap<>(); // 題號 -> 題目
Map<Integer, String> answerMap = new HashMap<>(); // 題號 -> 正確答案
for (int i = 0; i < numOfQuestions; i++) {
String line = scanner.nextLine().trim();
// 解析題號、題目內容和正確答案
int nIndex = line.indexOf("#N:") + 3;
int qIndex = line.indexOf("#Q:");
int aIndex = line.indexOf("#A:");
int questionNumber = Integer.parseInt(line.substring(nIndex, qIndex).trim());
String questionContent = line.substring(qIndex + 3, aIndex).trim();
String correctAnswer = line.substring(aIndex + 3).trim();
// 將題號和題目存入 questionMap,題號和正確答案存入 answerMap
questionMap.put(questionNumber, questionContent);
answerMap.put(questionNumber, correctAnswer);
}
點選檢視程式碼
String answerLine = scanner.nextLine().trim();
List<String> userAnswers = new ArrayList<>();
while (!answerLine.equals("end")) {
String[] answers = answerLine.split("\\s+");
for (String ans : answers) {
userAnswers.add(ans.substring(3)); // 移除 "#A:" 部分,保留答案內容
}
answerLine = scanner.nextLine().trim(); // 繼續讀取下一行直到 "end"
}
點選檢視程式碼
List<Integer> sortedKeys = new ArrayList<>(questionMap.keySet());
Collections.sort(sortedKeys); // 按題號順序輸出題目
List<String> results = new ArrayList<>();
for (int i = 0; i < sortedKeys.size(); i++) {
int questionNumber = sortedKeys.get(i);
String questionContent = questionMap.get(questionNumber);
String userAnswer = userAnswers.get(i);
// 輸出格式:題目內容+" ~"+使用者的答案
System.out.println(questionContent + "~" + userAnswer);
// 判斷答案是否正確,儲存判題結果
if (answerMap.get(questionNumber).equals(userAnswer)) {
results.add("true");
} else {
results.add("false");
}
}
- 第二題設計與分析
1.程式設計了三個類來對應考試系統的不同組成部分:
Question類:包含題目ID、內容和正確答案。這是一個簡單的模型類,用於儲存題目的基本資訊。
TestPaper類:代表試卷物件,包含試卷ID、題目-分數的對映關係,以及試卷的總分。該類可以實現試卷和題目之間的關係對映,利用了Java的Map資料結構。
AnswerSheet類:表示考生的答題卡,包含考生使用的試卷ID和考生作答的答案列表。
- Java集合和資料結構
Map介面和實現類:HashMap和LinkedHashMap用於儲存和對映關係。HashMap儲存了所有題目資訊(questionMap),並根據題目ID快速查詢題目資訊;LinkedHashMap在TestPaper類中用於保持題目新增的順序(因為順序會影響輸出結果的順序)。
ArrayList:在AnswerSheet類中使用List儲存考生的答案順序,以便逐題對比和得分計算。
Scanner類:透過Scanner類讀取使用者從控制檯輸入的資料。逐行讀取、解析並儲存在適當的資料結構中。 - 字串解析與處理
‘#N:開頭表示題目資訊,格式解析為題目ID、內容和正確答案。
‘#T:開頭表示試卷資訊,解析試卷ID和題目-分數對。
‘S:開頭表示答題卡資訊,解析試卷ID和考生的各個答案。
字串擷取:透過substring方法提取字串中的子字串。例如從#T:字串中獲取試卷ID。 - 基礎演算法與邏輯控制
總分驗證:TestPaper類中提供了checkFullScore方法,用於驗證試卷的總分是否達到100分。主程式在處理完所有試卷後,檢查所有試卷的總分是否正確,並輸出提示資訊。
答案匹配與得分計算:在主程式中遍歷答題卡的答案,並將其與對應題目的正確答案進行比對。對於每個答題:
如果考生答案正確,則記錄該題的分數;否則記錄為0分。
累加每題的得分來計算考生的總得分。 - 異常與特殊情況處理
試卷總分不達標提示:輸出提醒,如果某份試卷的總分不等於100分,顯示提醒資訊。
無效答題卡處理:若考生答題卡上的試卷ID在系統中不存在,程式會提示“試卷號不存在”。
缺失答案處理:若考生答題卡缺少題目答案時,輸出“answer is null”,並記錄該題得分為0。
題目資訊缺失:在答案對比時,若沒有找到對應的題目資訊(即questionMap中沒有該題ID),同樣記錄為0分。
- 第二題改進建議
1.Question 類
點選檢視程式碼
class Question {
int id;
String content;
String answer;
public Question(int id, String content, String answer) {
this.id = id;
this.content = content;
this.answer = answer;
}
}
點選檢視程式碼
class TestPaper {
int id;
Map<Integer, Integer> questions = new LinkedHashMap<>();
int totalScore = 0;
public TestPaper(int id) {
this.id = id;
}
public void addQuestion(int qId, int score) {
questions.put(qId, score);
totalScore += score;
}
public boolean checkFullScore() {
return totalScore == 100;
}
}
點選檢視程式碼
class AnswerSheet {
int testPaperId;
List<String> answers = new ArrayList<>();
public AnswerSheet(int testPaperId) {
this.testPaperId = testPaperId;
}
public void addAnswer(String answer) {
answers.add(answer);
}
}
-
第三題設計與分析
1. 類的設計
該程式由多個類構成,每個類承擔特定的職責,透過組合使用實現了較為清晰的層次結構。類之間的資料和功能分離,充分體現了物件導向的設計原則。
2. Question 類
職責:代表考試系統中的一道題目,包含題目內容、答案和唯一識別符號(題目ID)。
屬性:
id:題目ID,型別為int,用於唯一標識一道題目。
content:題目內容,型別為String。
answer:題目的正確答案,型別為String。
設計分析:
透過構造器 Question(int id, String content, String answer) 初始化每道題目的ID、內容和答案。
由於類中沒有複雜的邏輯,僅用於儲存資料,因此沒有額外方法,實現簡單直接。
3.TestPaper 類
職責:代表一份試卷,包含多個題目及每個題目的分數,並提供檢測總分是否滿足滿分要求的功能。
屬性:
id:試卷ID,型別為int。
questions:儲存題目ID及對應分數的Map<Integer, Integer>,鍵為題目ID,值為分數,使用LinkedHashMap來確保題目的插入順序。
totalScore:試卷的總分數,型別為int,動態更新每道題目分數累加的總和。
方法:
addQuestion(int qId, int score):新增題目及分數到試卷中,並累加總分。
checkFullScore():檢查試卷的滿分是否為100,若不滿足則可以發出警告。
設計分析:
試卷類以Map儲存題目ID與分數,方便查詢題目分數。使用LinkedHashMap確保按題目新增順序儲存,方便後續與答卷對應。
滿分檢查功能分離到checkFullScore()方法中,使程式碼更具可讀性。
4. AnswerSheet 類
職責:記錄學生的答卷,包含答卷對應的試卷ID、學生ID及題目的作答情況。
屬性:
testPaperId:試卷ID,型別為int。
studentId:學生ID,型別為String,用於標識答卷歸屬的學生。
answers:儲存學生每題答案的List,按題目順序儲存。
方法:
addAnswer(String answer):將一個題目的答案新增到answers列表。
設計分析:
AnswerSheet類儲存答卷的學生ID、試卷ID及答案,且答案列表與試卷的題目列表對應。利用addAnswer方法將答案逐題新增,確保順序一致。
5. Student 類
職責:代表學生的基本資訊,包含學生ID和姓名。
屬性:
id:學生ID,型別為String。
name:學生姓名,型別為String。
設計分析:
Student類僅儲存學生的基本資訊,並透過構造器初始化。設計簡單,但在程式中透過學生ID關聯答卷和學生。
6. Main 類
職責:程式的入口,控制資料的輸入、處理和輸出。
主要功能:
初始化和維護題目、試卷、答卷和學生的集合。
控制資料輸入和解析,處理資料異常,驗證資料的合法性。
執行評分流程,輸出每個學生的答題結果和總分。
7. 資料結構分析
HashMap:用於儲存題目、試卷、學生資料,查詢效能優異。因為題目、學生和試卷ID在整個系統中都是唯一的,這些資料適合用HashMap儲存。
LinkedHashMap:用於TestPaper類中的questions,它能保證題目在試卷中按新增順序排列。
ArrayList:用於儲存答卷中的答案列表,按順序新增答案,易於與題目列表一一對應。
HashSet:用於儲存被刪除題目的ID,用於快速查詢判斷題目是否已被刪除。 -
第三題改進建議
1.Question 類
點選檢視程式碼
class Question {
int id;
String content;
String answer;
public Question(int id, String content, String answer) {
this.id = id;
this.content = content;
this.answer = answer;
}
}
點選檢視程式碼
class TestPaper {
int id;
Map<Integer, Integer> questions = new LinkedHashMap<>();
int totalScore = 0;
public TestPaper(int id) {
this.id = id;
}
public void addQuestion(int qId, int score) {
questions.put(qId, score);
totalScore += score;
}
public boolean checkFullScore() {
return totalScore == 100;
}
}
點選檢視程式碼
class AnswerSheet {
int testPaperId;
String studentId;
List<String> answers = new ArrayList<>();
public AnswerSheet(int testPaperId, String studentId) {
this.testPaperId = testPaperId;
this.studentId = studentId;
}
public void addAnswer(String answer) {
answers.add(answer);
}
}
-
踩坑心得
1. 輸入資料格式不規範
坑:題目內容和答題資訊的格式不符合規範,如沒有指定字首(#N:、#Q:、#A:),或輸入內容缺少某些欄位。比如,題目描述的格式是 #N:1 #Q:1+1= #A:2,而使用者可能輸入 #N:1 #Q:1+1= 2。
解決辦法:在解析字串時,首先檢查格式的完整性。例如,確保字串包含所有需要的標記符並且順序正確。如果不符合格式要求,可以跳過該行或輸出提示資訊告知使用者輸入格式有誤。
心得:格式檢查是確保程式健壯性的第一步,特別是在處理使用者輸入時要儘可能避免假設輸入總是正確的。
2. 題號順序與輸入順序不一致
坑:題號的順序不一定是按順序輸入的,因此直接按輸入順序儲存並輸出會導致題目錯位。
解決辦法:將題目存入 Map 中,以題號作為鍵,然後在輸出時將題號排序,以保證輸出的題目順序正確。
心得:在程式邏輯上儘量減少對“順序性”輸入的依賴,使用 Map 這種鍵值結構可以更靈活地處理題目順序問題。
3. 題號重複
坑:如果輸入中出現重複的題號,程式直接儲存會導致覆蓋之前的題目資訊或答案,導致最終輸出結果錯誤。
解決辦法:在插入 Map 之前檢查是否已包含該題號。如果題號重複,可以選擇跳過或記錄並告知使用者重複。
心得:提前識別重複資料有助於提升程式的可靠性,特別是題號這樣的關鍵欄位應保持唯一性。
4. 題目數量和答案數量不匹配
坑:如果使用者輸入的答題數量少於或多於題目數量,直接處理會導致 IndexOutOfBoundsException 或漏判部分題目。
解決辦法:在處理答題資訊之前,檢查答題的數量是否與題目數量一致。若不一致,可以在程式結束時給出提示。
心得:對於數量不匹配的情況,及時給出反饋或提示可以幫助使用者快速發現輸入中的問題,而不是等到程式出錯才發現。
5. 字串操作錯誤
坑:使用 indexOf() 和 substring() 等方法提取題目和答案時,若標記符未找到,會返回 -1,進而導致 substring() 產生異常。
解決辦法:在執行字串操作前,先判斷標記符的位置是否有效。例如,如果 line.indexOf("#Q:") == -1,則說明題目內容缺失,應跳過該行。
心得:字串解析要特別小心,特別是使用 indexOf() 和 substring() 時,確保位置合法性,避免處理異常情況時出錯。
6. 不合理的異常處理
坑:如果沒有捕獲可能的異常,或捕獲異常後沒有詳細的錯誤資訊提示,程式會在執行時崩潰,使用者可能不知道原因。
解決辦法:使用 try-catch 捕獲解析和型別轉換中的常見異常,如 NumberFormatException 和 IndexOutOfBoundsException,並輸出具體的錯誤資訊,讓使用者瞭解問題所在。
心得:良好的異常處理不僅有助於除錯,還能提供使用者友好的反饋,避免程式在輸入不合規時直接崩潰。
7. 答案判定中的大小寫或空格問題
坑:在判定答案的正確性時,字串的大小寫或多餘空格可能導致答案被錯誤地判斷為不正確。
解決辦法:在判題時使用 trim() 去除空格,或使用 equalsIgnoreCase() 進行大小寫不敏感的比較(如果題目允許)。
心得:使用者輸入的答案可能不嚴格遵循大小寫格式,適當的預處理會讓程式對使用者更友好。
8. 題號排序與答案輸出順序對不上
坑:題號的排序和答題資訊的順序不匹配,導致答案輸出和題目內容不對應。
解決辦法:題號排序後,按題號順序依次匹配答案並輸出。可以用 List 將題號排序後再按順序輸出。
心得:保證題目與答案的對應關係,特別是在輸出時,確保順序一致性會極大地提升使用者的使用體驗。
9. Scanner 輸入處理中的“殘餘換行”問題
坑:使用 nextInt() 讀取數字後,再使用 nextLine() 會讀取到換行符,導致資料不完整。
解決辦法:儘量使用 nextLine(),然後用 Integer.parseInt() 將字串轉為整數,以避免遺留的換行符干擾。
心得:Scanner 的輸入方法之間有時會產生不必要的“行殘留”,建議保持輸入方式的一致性,避免遺漏重要資料。
10. 使用不恰當的資料結構
坑:如果直接使用 List 或陣列來儲存題目和答案,不僅在查詢和排序上更麻煩,還容易出現順序錯位。
解決辦法:合理選擇 Map 或 List 結構。Map 適合題號和題目資訊的對映儲存,而 List 則適合順序資料如使用者答題記錄。
心得:在題目和答案對照、順序輸出等任務中,適當的資料結構選擇可以減少不必要的複雜度,提升程式碼的簡潔性。 -
總結
1.學到的內容
物件導向設計:程式碼透過Question、TestPaper、AnswerSheet和Student等類來封裝資料結構,體現了物件導向設計思想,有助於模組化和程式碼複用。
集合和資料結構的靈活應用:程式碼中大量使用了Map、List和Set來管理題目、試卷、答卷和學生資訊,並高效地進行資料檢索和刪除操作。
資料解析和輸入驗證:透過Scanner讀取輸入,使用字串解析和異常處理來識別不同型別的資料結構,增強了程式碼的健壯性。
條件分支和異常處理:利用try-catch塊和if-else邏輯分支來捕捉並處理潛在的輸入錯誤,確保系統在處理異常輸入時不崩潰。
2.需要進一步學習和研究的方面
異常處理改進:當前程式碼僅在輸入解析階段進行簡單的格式驗證,後續需要對資料缺失(如題目不存在、答案為空等)做更精細的異常處理,提升系統的穩健性。
程式碼最佳化:可以將評分過程和輸入解析過程模組化,提取到單獨的方法中,減少main方法的複雜度,增強程式碼的可讀性和可維護性。
單元測試:引入JUnit等測試框架,對各個模組進行單元測試,以驗證輸入解析、評分等功能的正確性,確保系統的可靠性。
資料持久化:當前程式碼僅使用記憶體資料結構來管理題目、試卷和答卷,進一步可以探索資料持久化(如資料庫儲存)以便在多次執行中保持資料狀態。
擴充套件性:可以考慮增加更多的功能,例如記錄答卷提交時間、支援批次刪除題目、實現多份試卷的分數統計等,以提升系統的靈活性和實用性。