一、前言
在過去幾周的Java程式設計學習中,透過三組題目集的練習,我逐步深入掌握了從基礎語法到物件導向程式設計、資料結構、異常處理,以及輸入輸出操作等多個核心概念。這些練習不僅加強了我的基礎程式設計技巧,還逐步引入了更復雜的資料結構和演算法應用,使我的程式設計能力和問題解決技巧得到了顯著提升。
題目集1共有5道題,著重於Java基礎,涉及類的設計與建立、物件例項化、方法實現及類、陣列的基本運用、ArrayList的運用、還有關聯類的基本使用原則。
題目集2共有4道題,在題目集1的基礎上提升了難度,主要有Comparable介面的實現、類與物件的應用、還涉及ArrayList以及HashMap的運用。
題目集3共有3道題,進一步擴充套件了物件導向的概念,包括繼承、多型和封裝、日期類的基本使用、異常處理和IO操作、還涉及List以及HashMap的運用。
二、設計與分析
題目集1的最後一題分析
設計類圖與時序圖如下
本題的設計思路是實現一個簡單的問答系統,它能夠讓使用者輸入一系列問題和答案,然後提交答案,系統會驗證答案的正確性並給出反饋。系統由三個主要的類組成:Question、Paper和Answer。
- Question類:表示單個問題,包含問題順序、問題內容和正確答案。它還包含一個方法來檢查給定的答案是否正確。
- Paper類:代表一套試卷,用於管理多個Question物件。它提供了新增問題的方法和獲取排序後的問題列表的方法。
- Answer類:用於收集使用者的答案並驗證答案的正確性。它儲存了答案和對應的結果,並提供了一個方法來列印問題和使用者的答案以及驗證結果。
執行流程:
• 透過Scanner類讀取使用者輸入的問題數量,然後迴圈讀取每個問題的具體資訊,並建立Question物件存入Paper物件中。
• 使用者提交答案時,透過AnswerCollection方法收集答案,並儲存在Answer物件中。
• 使用checkAnswers方法驗證每個答案的正確性,並將結果儲存在results列表中。
• 最後,使用print方法輸出每個問題的題目和使用者的答案,以及答案的正確與否。
題目集2的最後一題分析
設計類圖與時序圖如下
本題的設計思路是實現一個更復雜的考試系統,其中包括多個試卷、問題和答案,在題目集1的基礎上增加了questionScores對映,用於儲存每個問題及其對應分數。這允許系統計算每個問題的分數,並在最後計算總分。還增加了printAlertIfNecessary方法,用於檢查試卷的總分是否為100分。如果不是,將列印一條警告資訊。該系統能夠處理試卷的建立、問題的新增、學生答案的收集、答案的校驗以及分數的計算。系統由四個主要的類組成:Question、Paper、Answer和一個主類Main。
- Question類:表示單個問題,包含問題順序、問題內容和正確答案。它還包含一個方法來檢查給定的答案是否正確。
- Paper類:代表一套試卷,用於管理多個Question物件。它提供了新增問題的方法、根據問題順序獲取排序後的問題列表的方法以及計算分數的方法。
- Answer類:用於收集學生的答案並驗證答案的正確性。它儲存了答案和對應的結果,並提供了一個方法來列印問題、學生的答案以及驗證結果。
- Main類:作為程式的入口點,負責讀取輸入、建立試卷、新增問題、收集答案、校驗答案並輸出結果。
執行流程:
• 使用Scanner類讀取控制檯輸入,處理包括試卷編號、問題順序、問題內容、正確答案和學生答案等資訊。
• 透過Paper類管理試卷,addQuestion方法用於向試卷中新增問題,同時記錄每個問題的分數。getQuestionsSorted方法確保問題按順序排列。
• Answer類負責收集答案並透過checkAnswers方法校驗答案的正確性,結果儲存在results列表中。
• Paper類的calculateScores方法根據學生的答案和每道題的分數計算總分,並可透過printAlertIfNecessary方法檢查試卷總分是否為100分,如果不是,則列印警告資訊。
• 在處理輸入時,程式碼透過判斷currentPaper是否存在來避免NullPointerException。
• 在所有答案處理完畢後,Answer類的print方法用於輸出每個問題的題目、學生的答案以及答案的正確與否。同時,calculateScores方法輸出學生的總分。
整體上,程式碼可實現試卷和問題的靈活管理,允許動態新增問題和試卷,可實現答案的收集和校驗,還提供了基本的測試評分功能。透過物件導向的方法將考試系統的各個組成部分進行了有效的封裝和模組化,使得每個類的職責明確,易於理解和維護。然而,程式碼的實際執行和效能還需要進一步的測試和最佳化,以確保在各種輸入情況下都能正確執行。
題目集3的最後一題分析
設計類圖與時序圖如下
本題的設計思路是實現一個綜合的考試系統,能夠處理複雜的考試流程,包括題目管理、試卷建立、學生資訊管理、答案收集與評分。系統採用物件導向的方法,將不同的功能封裝在不同的類中,以提高程式碼的可讀性和可維護性。以下是各個類的設計思路:
- Question類:該類代表單個考試題目,包含題目的ID、內容和正確答案,以及一個標識題目是否有效的布林值。它提供了方法來檢查答案的正確性,並能標記題目為無效。
- Paper類:代表一套試卷,包含題目列表、題目順序和題目分數的對映。它提供了新增題目、獲取排序後題目列表和計算分數的方法。printAlertIfNecessary方法用於在試卷總分不為100分時列印警告資訊。
- Answer類:用於處理學生的答案,包括答案的收集和校驗。它儲存了答案和校驗結果,並提供了方法來列印每個問題的答案和校驗結果。
- ExamSystem類:是整個考試系統的中樞,負責管理所有的題目、試卷、學生資訊和答案。它提供了新增題目、刪除題目、新增試卷、新增學生資訊和處理答案的方法。run方法是程式的入口點,負責讀取輸入並根據輸入型別執行相應的操作。
- Main類:包含main方法,是程式的入口。它建立ExamSystem的例項並呼叫run方法來啟動整個系統。
執行流程:
• 系統啟動後,透過ExamSystem類的run方法讀取使用者的輸入。
• 根據輸入的指令,執行新增題目、新增試卷、新增學生資訊、處理答案等操作。
• 答案處理完畢後,呼叫processAllAnswers方法來計算分數並輸出每個學生的答案和得分情況。
三、採坑心得
在提交原始碼的過程中,我遇到了以下問題:
1.正規表示式運用不熟練
在做題目集1時,對正規表示式的運用還不太瞭解,導致在字串分割獲取題目序號、題目內容及答案時,老是出現分割不準確問題。以分割題目序號為例:
由於輸入格式為#N:1 #Q:1+1= #A:2
序號後面有一個空格,導致不能從String型別轉換為int型別,因此需要.trim()來去除字串兩端空白字元後再將字串轉換為int。
當獲取題目內容及答案時,若未進行正確的正規表示式操作則會出現格式錯誤!
2.排序問題
在題目集2中,最初我沒有正確地按照試卷題目順序實現問題排序,導致問題與答案不對應。後面增加了問題排序類後,解決了這個問題。
public List<Question> getQuestionsSorted() {
List<Question> questionsSorted = new ArrayList<>();
for (int order : questionOrders) {
for (Question question : questions) {
if (question.getOrder() == order) {
questionsSorted.add(question);
break;
}
}
}
return questionsSorted;
}
3.NullPointerException異常
在題目集2中,當答卷缺失部分答案或為無效的試卷號時就會丟擲NullPointerException,這是因為訪問或操作的物件是一個null物件。不過此問題目前還沒有解決,後面會努力解決的!
4.失效提示
在題目集3中,一開始刪除題目這一部分老是透過不了,因為當題目被刪除後,輸出時需顯示the question x invalid~0,在計算總分時也會導致相應的改變(所刪除題目分數為0),刪除題目的實現主要由兩部分程式碼組成:
Questin類中
public void invalidate() {
this.isValid = false;
}
ExamSystem類中
public void deleteQuestion(String info) {
int id = Integer.parseInt(info.split("-")[1].trim());
Question q = allQuestions.get(id);
if (q != null) {
q.invalidate();
}
else {
System.out.println("non-existent question~0");
}
}
四、改進建議
題目集2最後一題:
需改進NullPointerException異常問題
這個異常是在Paper.addQuestion方法呼叫時丟擲的,這就意味著傳遞給addQuestion方法的引數之一是null。
為了解決這個問題,可以採取以下措施:
- 確保物件初始化:在呼叫addQuestion之前,確保所有需要的物件都已經正確初始化。確保Question物件q不是null,並且Paper物件paper也已經正確建立並初始化。
- 引數校驗:在addQuestion方法中新增引數校驗,確保傳入的Question物件不是null。如果是null,則不執行新增操作或丟擲一個更具體的異常來指明問題所在。
public void addQuestion(Question question, int score) {
if (question == null) {
throw new IllegalArgumentException("Question cannot be null");
}
questions.add(question);
questionOrders.add(question.getOrder());
questionScores.put(question.getOrder(), score);
}
確定問題所在後,再透過需求進一步最佳化程式碼!
這個NullPointerException異常是在Answer類的checkAnswers方法中丟擲的,具體是在Main.java的第96行。要解決這個問題,我們需要確保在呼叫checkAnswers方法之前,Answer類中的所有物件都已經被正確初始化,不是null。以下是改進措施:
在main()方法中的switch (parts[0]){}裡的case "#S":Paper currentPaper = papers.get(answerPaperId);後面增加以下程式碼即可解決
if (currentPaper == null) {
System.out.println("The test paper number does not exist.");
break;
}
題目集3最後一題:
此需要改進的地方還有很多,以下是改進方向:
- 處理不存在的題目引用:
當試卷引用了不存在的題目時,應輸出“non-existent question~0”。需要在Paper類中新增程式碼以處理這種情況。 - 處理答案數量與試卷題目數量不匹配的情況:
當答案數量少於試卷的題目數量,缺失的答案處應輸出“answer is null”。需要在Answer類中新增程式碼以處理這種情況。 - 處理學號引用錯誤:
如果答卷中的學號不在學生列表中,應在輸出判分資訊時提示錯誤。需要在ExamSystem類中新增程式碼以檢查學號是否存在。 - 最佳化Paper類的calculateScores方法:
確保在計算分數時,只有有效的答案才會被計分。如果題目被刪除或不存在,相應的分數應為0。 - 最佳化學生資訊的處理:
在ExamSystem類中,確保學生資訊被正確處理,並且在輸出判分資訊時,能夠正確地關聯學生ID和姓名。
五、總結
透過這三次的題目集,我深刻體會到了Java程式設計的挑戰性,三次大作業難度逐步提升,儘管分數不太理想,但在做題和後續最佳化程式碼的過程中,我學到了不少東西:對正規表示式運用有了更深刻的理解、對ArrayList、HashMap等資料結構有了更熟練的運用。物件導向設計方面,我更加熟悉瞭如何定義類、建立物件以及如何透過例項方法和類方法來實現功能,對封裝、繼承和多型等核心概念有了更深入的認識。這些經驗讓我在編寫和理解程式碼時更加得心應手!此外,我還意識到了程式碼的可讀性和可維護性的重要性,學會了如何編寫更清晰、更模組化的程式碼,為後續最佳化程式碼時理解原始碼提供了極大幫助。
在未來的學習中,希望我能有更強的動手能力,在題目中不斷實踐和應用所學的知識,以逐步提高程式設計技能和解決問題的能力。