Java前三次大作业总结

一、前言

  1. 知识点总结与版本更迭

    (1) 知识点总结:

    • 类与对象:包括 Question、ExamPaper、AnswerSheet 三个类,以及它们的构造方法、属性和方法,帮助理解类和对象的使用。
    • 封装:各类属性为私有,通过公共方法访问,展示了面向对象编程中封装的基本概念。
    • 关联关系:ExamPaper 中包含多个 Question 对象,AnswerSheet 关联 ExamPaper,展示了类之间的关联关系。
    • Map接口 (TreeMap):在 ExamPaper 中用 TreeMap 按照题号顺序存储 Question 对象,有助于理解键值对的使用和排序特性。
    • List接口 (ArrayList):用来存储和返回题目列表,帮助学生理解列表的基本操作和用法。
    • 字符串操作:使用 String 的 split、trim 方法,解析用户输入,帮助理解字符串操作的重要性。
    • 正则表达式:通过 split 方法的参数处理输入格式。正则表达式可能会稍显复杂,但能提高代码的灵活性和健壮性。
    • 数组的定义与操作:AnswerSheet 类中的 answers 和 results 数组用来记录用户和判分结果,帮助理解数组的初始化和遍历。
    • Scanner类:用于获取用户输入。对于初学者而言,Scanner 是获取命令行输入的标准方法。
    • 标准输出:使用 System.out.println 来输出每道题的内容、答案和判分结果。
      (2) 题目2功能迭代:
      相较于上一个代码而言新增了以下几个功能:
      更完善的输入解析和数据存储
    • 通过 InputHandler 类集中管理输入解析,将题目、试卷和答卷的输入分别解析并存储到相应的数据结构中(Map<Integer, Question>,Map<Integer, TestPaper> 和 List)。这提高了代码的结构化程度和可读性,增强了程序的扩展性和维护性。
    • InputHandler 使用了 Scanner 类来接收和处理用户输入,通过 #N:、#T:、#S: 标记来区分不同类型的数据。这种方式可以灵活地处理多种输入格式。
      数据完整性检查和异常处理:
    • TestPaper 类中增加了 isValid 方法来检查试卷的总分是否为 100 分,并在试卷总分不符合要求时输出警告信息(alert: full score of test paper...),防止输入错误的试卷分数。
    • 在 AnswerSheet 的 grade 方法中增加了试卷 ID 的存在性检查,通过 testPaperMap.containsKey 方法验证试卷是否存在并进行处理,避免了因缺少试卷导致的程序错误。
      答案判分逻辑的改进:
    • grade 方法中增加了对答案是否为 null 的检查,避免了因缺失答案而导致的判分错误。在没有提供答案的情况下,系统会输出 "answer is null" 并记录 0 分。
    • 对于每个题目,代码会检查学生答案是否正确并计算相应的得分,将每个题目的分数存储在 scores 列表中,并最终计算和输出总分。这种方法增强了判分逻辑的鲁棒性。
      (3) 题目3功能迭代:
      相较于上一个版本,该代码新增了以下功能和知识点:
    • 软删除功能的实现:通过 Question 类中的 deleted 标记来表示题目是否已被删除,并在相应的逻辑中对其进行检查,如评分时忽略已删除的题目,确保已删除的题目不影响成绩评定。
    • 异常处理和输入格式验证的增强:在每个正则匹配的操作中,增加了 try-catch 语句来捕获格式不符合预期的情况,例如对输入不符合规范时输出 wrong format 提示。通过对正则匹配进行细粒度的控制,增强了对用户输入的错误检测和反馈。
    • 答案的解析改进:在解析学生答案时,添加了对 #A 标签的识别,从而可以处理输入中不同题号的学生答案。这解决了学生答案顺序和题目编号不一致的问题,提高了输入的灵活性。
    • 支持多个学生信息的录入:通过解析 #X 标签,允许在一次输入中录入多个学生的编号和姓名,提供了更灵活的输入方式。
    • 多种警告信息输出:如试卷总分不等于 100 分时,通过 alerts 列表记录警告,并在最后统一输出,提升了系统的用户友好性和警告管理的清晰度。
    • 删除题目的输入格式解析:通过 #D 标签对输入格式进行解析,删除特定题目(通过题目编号),并在评分过程中忽略这些题目,从而有效地支持题目的动态调整。
    • 答卷和题目编号的映射改进:在 AnswerSheet 类中,通过 addAnswer 方法实现了题号和答案的存储,解决了答题顺序可能不一致的问题。同时,在评分过程中,确保按照试卷中题目编号的顺序进行答案检查。
    • 改进的评分和答题情况输出:在 printStudentScore 中,添加了对学生成绩的格式化输出,将每题得分和总分按指定格式输出,方便用户阅读成绩结果。
      这些新增的功能和优化进一步提高了系统的健壮性灵活性用户友好性。在代码实现上,通过引入正则表达式解析、异常处理、软删除标记等知识点,使代码在处理复杂输入时具备更好的容错能力和扩展性。
  2. 题量与难度
    (1) 题目1:
    从代码结构来讲,本题目涉及多个类,具有一定的复杂度,要求我们具有一定的面向对象编程基础。在编写过程中对类的关联关系和方法调用的使用有一定的挑战性,特别是在理解ExamPaper和Answer Sheet之间的关系时。从集合框架和字符串处理来讲,Map和List是Java中比较常用的集合,难度对于我们来说是中等水平,而题目中对输入字符串的方式涉及正则表达式,对尚未深入学习字符串处理的我们来说是稍微有点挑战性的。而数组操作和输入输出处理则是属于比较简单的部分可以轻松掌握。
    总的来说,第一次作业涉及多个类,集合操作,字符串处理等内容,对于理解和应用面向对象编程和集合框架的能力有较高要求,综合难度为中等偏上。
    (2) 题目2:
    该代码通过面向对象设计将系统分为多个职责明确的类,主要包含题目管理、试卷生成、答卷处理和输入解析等模块。代码中的 Question、TestPaper 和 AnswerSheet 类分别承担了题目信息的存储、试卷的组织和评分等功能,遵循了单一职责原则,使各类易于维护和扩展。例如,Question 类不仅存储题目和答案,还包含评分逻辑,而 TestPaper 负责收集和管理多道 Question,并计算总分,这种设计方便拓展题库和试卷生成。
    此外,InputHandler 类集中管理用户输入的处理和验证,通过捕获异常和判断空值等方式,提升了程序的健壮性。代码使用 Java 的集合框架来存储和查找题目及答案,如 Map 结构快速查找特定题目、List 用于存储用户答案等,并借助 Java 流式 API 实现数据的高效处理。流式 API 提高了代码简洁性,例如在计算总分或过滤数据时,减少了冗长的循环语句。这些设计体现了代码结构的清晰性和良好的可扩展性,但对开发者的 Java 集合类、流式 API 的应用理解提出了要求。同时,输入处理较为复杂,需熟练掌握字符串解析与异常处理的相关方法。
    总体来说,这套代码难度较高,适合有一定面向对象基础并熟悉 Java 高级特性的开发者。
    (3) 题目3:
    相较于前两个版本,目前代码的复杂性显著提升,主要体现在数据处理逻辑、模块协同以及健壮性设计上。现在的代码通过正则表达式解析多种输入模式,支持灵活的输入操作,例如删除题目和添加多位学生。这使得系统需要对正则表达式有更深的理解。同时,面向对象设计上,各个类之间的依赖关系变得更加紧密,例如 AnswerSheet 中的判分逻辑需要依赖 TestPaperQuestion 的信息,并且要考虑题目是否被删除、答案缺失等情况,这使得数据一致性和模块间的高内聚性尤为重要。此外,代码增加了多层次的异常处理,通过详细的错误提示和反馈来确保用户输入错误不会导致系统崩溃。在健壮性设计方面,例如试卷满分验证、删除题目后的评分处理、缺失答案得 0 分等,这些边界条件的处理细节提升了代码的健壮性,同时也对开发者的边界考虑和异常处理能力提出了更高要求。总体来看,当前代码实现难度更高,需要开发者具备较好的面向对象设计、正则表达式解析、异常处理和系统健壮性设计能力。
    二、设计与分析

    1. 题目1的设计分析
      (1) Question 类
      职责:存储单个题目的信息,包括题号、题目内容和正确答案。
      设计分析:作为数据类,只提供基本的构造方法、获取题目信息和检查答案的功能。此类的设计较为简单,负责封装题目信息,确保题目内容与答案的一致性。

(2) ExamPaper 类
职责:管理整个试卷,存储多道 Question,并提供题目的增删、查找及题目列表生成的功能。
设计分析:使用 TreeMap<Integer, Question> 按题号顺序存储 Question 对象,通过题号排序的方式快速查找题目。此类集中管理所有题目内容,确保题号有序性,便于后续展示与遍历。

(3) AnswerSheet 类
职责:代表考生的答题卡,记录考生对每道题的**,并在提交后自动判分。
设计分析:AnswerSheet 使用数组保存考生的并存储每题的判分结果。grade 方法遍历试卷题目并逐题对比,判定是否正确。此类承担判分和输出的功能,封装了对考生答题情况的记录和判分逻辑

类图

  1. 题目2的设计分析
    (1)单一职责原则(SRP)与类设计
    Question 类负责存储题目信息及评分方法,包含属性如题干、选项、难度。
点击查看代码
class Question {
    int id;
    String questionContent;
    String correctAnswer;

    public Question(int id, String questionContent, String correctAnswer) {
        this.id = id;
        this.questionContent = questionContent.trim();
        this.correctAnswer = correctAnswer.trim();
    }

    public boolean checkAnswer(String answer) {
        return correctAnswer.equals(answer.trim());
    }
}
TestPaper 类管理试卷,包括按类型和难度分配题目及生成题目列表的功能。
点击查看代码
class TestPaper {
    int paperId;
    List<Integer> questionIds = new ArrayList<>();
    List<Integer> questionScores = new ArrayList<>();
    int totalScore = 0;

    public TestPaper(int paperId) {
        this.paperId = paperId;
    }

    public void addQuestion(int questionId, int score) {
        questionIds.add(questionId);
        questionScores.add(score);
        totalScore += score;
    }

    public boolean isValid() {
        return totalScore == 100;
    }

    public int getQuestionScore(int index) {
        return questionScores.get(index);
    }
}
AnswerSheet 类处理用户答卷和评分逻辑,提供按题目逐项核对答案的功能。
点击查看代码
// 答卷类
class AnswerSheet {
    int paperId;
    List<String> answers = new ArrayList<>();
    List<Integer> scores = new ArrayList<>();
    int totalScore = 0;

    public AnswerSheet(int paperId) {
        this.paperId = paperId;
    }

    public void addAnswer(String answer) {
        answers.add(answer);
    }

    public void grade(TestPaper testPaper, Map<Integer, Question> questionMap, Map<Integer, TestPaper> testPaperMap) {
        // 检查试卷是否存在
        if (!testPaperMap.containsKey(paperId)) {
            System.out.println("The test paper number does not exist");
            return;
        }
        for (int i = 0; i < testPaper.questionIds.size(); i++) {
            int questionId = testPaper.questionIds.get(i);
            Question question = questionMap.get(questionId);
            String answer = (i < answers.size()) ? answers.get(i) : null;

            // 如果答案为空,输出 "answer is null"
            if (answer == null) {
                System.out.println("answer is null");
                scores.add(0); // 记录 0 分
            } else {
                // 检查答案是否正确
                boolean correct = question.checkAnswer(answer);
                System.out.println(question.questionContent + "~" + answer + "~" + (correct ? "true" : "false"));
                int score = correct ? testPaper.getQuestionScore(i) : 0;
                scores.add(score);
            }
        }
    // 计算总分
    totalScore = scores.stream().mapToInt(Integer::intValue).sum();
    // 输出分数列表(格式为:分数之间用空格分隔)并加上 "~" 总分
    System.out.println(String.join(" ", scores.stream().map(String::valueOf).toArray(String[]::new)) + "~" + totalScore);
    }
}
InputHandler 类:负责处理用户输入和数据验证,将输入逻辑从业务逻辑中抽离出来,提高代码的清晰性和可维护性。
点击查看代码
class InputHandler {
    private Scanner scanner;
    private Map<Integer, Question> questionMap;
    private Map<Integer, TestPaper> testPaperMap;
    private List<AnswerSheet> answerSheets;

    public InputHandler() {
        scanner = new Scanner(System.in);
        questionMap = new HashMap<>();
        testPaperMap = new HashMap<>();
        answerSheets = new ArrayList<>();
    }

    public void handleInput() {
        while (true) {
            String input = scanner.nextLine().trim();
            if (input.equals("end")) break;

            if (input.startsWith("#N:")) {
                String[] parts = input.split(" #Q:| #A:");
                int questionId = Integer.parseInt(parts[0].substring(3).trim());
                String questionContent = parts[1].trim();
                String correctAnswer = parts[2].trim();
                questionMap.put(questionId, new Question(questionId, questionContent, correctAnswer));
            } else if (input.startsWith("#T:")) {
                String[] parts = input.split(" ");
                int paperId = Integer.parseInt(parts[0].substring(3).trim());
                TestPaper testPaper = testPaperMap.getOrDefault(paperId, new TestPaper(paperId));
                for (int i = 1; i < parts.length; i++) {
                    String[] qScore = parts[i].split("-");
                    int questionId = Integer.parseInt(qScore[0]);
                    int score = Integer.parseInt(qScore[1]);
                    testPaper.addQuestion(questionId, score);
                }
                testPaperMap.put(paperId, testPaper);
                if (!testPaper.isValid()) {
                    System.out.println("alert: full score of test paper" + paperId + " is not 100 points");
                }
            } else if (input.startsWith("#S:")) {
                String[] parts = input.split(" #A:");
                int paperId = Integer.parseInt(parts[0].substring(3).trim());
                AnswerSheet answerSheet = new AnswerSheet(paperId);
                for (int i = 1; i < parts.length; i++) {
                    answerSheet.addAnswer(parts[i].trim());
                }
                answerSheets.add(answerSheet);
            }
        }
    }

    public Map<Integer, Question> getQuestionMap() {
        return questionMap;
    }

    public Map<Integer, TestPaper> getTestPaperMap() {
        return testPaperMap;
    }

    public List<AnswerSheet> getAnswerSheets() {
        return answerSheets;
    }
}

类图

  1. 题目3的设计分析
    (1)模块化分工和对象层次结构
    系统采用面向对象的设计原则,将功能分解为多个独立的模块。核心类包括:
    Question类:用于描述单个题目,包括题目的文本、选项、正确答案等属性,还实现了题目的“软删除”功能。
    TestPaper类:负责管理多个题目的集合,形成一份试卷。该类不仅包含试卷的题目列表,还实现了试卷的有效性验证,确保试卷在使用前是完整且有效的。
    Student类:用于表示学生的基本信息和考试记录,负责与学生相关的身份标识和考试参与记录。
    AnswerSheet类:记录学生的答案,负责答卷的存储、答案的完整性检查和成绩计算功能。
    通过这种模块划分,系统实现了清晰的对象层次结构,每个类有明确的职责。这种结构提高了代码的可读性和模块独立性,减少了类之间的直接耦合。各个类的职责清晰,增强了代码的可扩展性,后续可在不影响其他模块的前提下对单一模块进行更新或扩展
    (2) 输入处理和正则表达式解析
    系统通过InputHandler类负责输入的统一处理。在实现上,InputHandler类利用正则表达式解析输入数据,如题目、试卷、学生信息、答卷等录入内容。具体步骤包括:
    识别输入模式:通过正则表达式匹配不同类型的数据,如题目格式、学生信息格式和答案格式等。
    动态解析输入:不同的输入结构(如题目和答案的格式)可能各不相同,通过正则表达式,InputHandler类可以灵活应对多种输入模式。这一设计使系统可以适应不同的数据输入格式,增强了系统的兼容性和适用性。
    错误处理:在解析过程中,如果输入格式不符合预期,InputHandler类可以抛出异常并提供详细错误提示,帮助用户纠正错误输入。
    这种设计极大地提高了系统的输入处理灵活性,但也增加了解析逻辑的复杂性。正则表达式解析不仅要求输入格式严格符合规则,还需要考虑输入的边界情况。
点击查看代码
        Pattern questionPattern = Pattern.compile("#N:(\\d+) #Q:(.+?) #A:(.+)");
        Pattern paperPattern = Pattern.compile("#T:(\\d+)((?: \\d+-\\d+)+)");
        Pattern studentPattern = Pattern.compile("#X:((?:\\w+ \\w+-?)+)");
        Pattern answerPattern = Pattern.compile("#S:(\\d+) (\\d+)((?: #A:\\d+-.+)+)");
        Pattern deletePattern = Pattern.compile("#D:N-(\\d+)");
点击查看代码
if (questionMatcher.matches()) {
                try {
                    int questionId = Integer.parseInt(questionMatcher.group(1));
                    String content = questionMatcher.group(2);
                    String correctAnswer = questionMatcher.group(3);
                    questions.put(questionId, new Question(questionId, content, correctAnswer));
                } catch (Exception e) {
                    System.out.println("wrong format:" + input);
                }
            } else if (paperMatcher.matches()) {
                try {
                    int paperId = Integer.parseInt(paperMatcher.group(1));
                    TestPaper paper = new TestPaper(paperId);
                    String[] qScores = paperMatcher.group(2).trim().split(" ");
                    for (String qScore : qScores) {
                        String[] parts = qScore.split("-");
                        int questionId = Integer.parseInt(parts[0]);
                        int score = Integer.parseInt(parts[1]);
                        paper.addQuestion(questionId, score);
                    }
                    testPapers.put(paperId, paper);
                    if (!paper.isValid()) alerts.add("alert: full score of test paper" + paperId + " is not 100 points");
                } catch (Exception e) {
                    System.out.println("wrong format:" + input);
                }
            } else if (studentMatcher.matches()) {
                try {
                    String[] studentInfo = studentMatcher.group(1).split("-");
                    for (String info : studentInfo) {
                        String[] parts = info.split(" ");
                        String id = parts[0];
                        String name = parts[1];
                        students.put(id, new Student(id, name));
                    }
                } catch (Exception e) {
                    System.out.println("wrong format:" + input);
                }
            } else if (answerMatcher.matches()) {
                try {
                    String[] parts = input.split("#");
                    int paperId = Integer.parseInt(answerMatcher.group(1));
                    String studentId = answerMatcher.group(2);
                    AnswerSheet sheet = new AnswerSheet(paperId, studentId);
                    if (parts.length > 2) {
                        for (int i = 2; i < parts.length; i++) {
                            if (parts[i].startsWith("A:")) {
                                int questionnum = Integer.parseInt(parts[i].split("-")[0].split(":")[1].trim());
                                String answer = parts[i].split("-")[1].trim();
                                sheet.addAnswer(questionnum, answer);
                            }
                        }
                    }
                    answerSheets.add(sheet);
                } catch (Exception e) {
                    System.out.println("wrong format:" + input);
                }
            } else if (deleteMatcher.matches()) {
                try {
                    int questionId = Integer.parseInt(deleteMatcher.group(1));
                    if (questions.containsKey(questionId)) {
                        questions.get(questionId).delete();
                    }
                } catch (Exception e) {
                    System.out.println("wrong format:" + input);
                }
            } else {
                System.out.println("wrong format:" + input);
            }
(3) 异常处理和健壮性设计 代码中实现了多层次的异常处理机制,分散在各个模块的关键方法中,确保系统在异常情况下能够正常运行并反馈友好的错误信息。例如: try-catch结构:在解析输入和判分过程中的各个环节中使用try-catch结构,确保即使某个输入出现异常也不会导致系统崩溃。每个输入处理步骤中都包含异常检测,若捕获到错误输入,系统会中止当前操作并反馈详细的错误信息。 模块级别的异常处理:各模块的关键方法中也设有异常检测和错误提示,如题目被删除或答案缺失的情况。系统会通过异常捕获机制为用户提供清晰的提示信息,提升用户的操作体验。 边界条件检测:在缺失数据的情况下,系统通过检测逻辑为每道题目提供默认处理方法,避免评分中出现“空指针”等错误。 通过这种设计,系统在处理错误输入或缺失数据时能够保持健壮,不会影响系统的整体运行。

三、采坑心得

  1. 题目1的采坑总结

问题:

  • 题号重复:在 ExamPaper 中,如果不检查题号的唯一性,可能会导致多个题目使用相同的题号,覆盖已存在的题目。应该确保每个题号唯一。

    • 解决办法:在 addQuestion() 方法中添加检查,确保没有重复题号。
  • 考生未答题:在 AnswerSheet 中,考生可能没有回答所有问题,导致空值出现。如果在评分时没有处理这个问题,可能会导致空指针异常。

    • 解决办法:在判分时要检查答题情况,如果题目没有作答,可以默认其为错误或提供提示。
  • 区分大小写或空格问题:在比较考生答案时,可能会忽略空格或大小写导致判分错误。

    • 解决办法:在 checkAnswer() 方法中,比较答案时可以使用 trim() 去除空格,并使用 equalsIgnoreCase() 忽略大小写。
  • 答案数组越界:如果 AnswerSheet 中记录的答案数量与 ExamPaper 中题目数量不一致,可能会导致数组越界异常。

    • 解决办法:在初始化 AnswerSheet 时,应确保答案数组的长度与试卷的题目数量一致,或者添加动态处理机制。
  • 题目不存在:在试卷中查找题目时,如果使用了不存在的题号,可能导致空指针异常。

    • 解决办法:在 getQuestion() 方法中,确保返回值不为 null,并提供异常处理机制

心得:
在编写和测试代码时,我也意识到很多潜在的错误点。例如,题号重复、答题记录不一致、判分逻辑不严谨、数组越界等问题,虽然看似简单,却容易被忽略。通过识别这些错误并设计防护机制,比如使用异常处理来应对边界情况,以及确保数据格式的正确性,让我更加清楚地认识到细节控制在系统稳定性中的重要性。

在这些错误的处理中,我深刻理解了输入校验的重要性。无论是题目的编号唯一性、题目内容和答案格式的匹配,还是对数组边界的检查,只有通过完整的数据校验,才能避免运行时错误,并保证系统的健壮性。这也让我明白了测试覆盖率的重要性,只有充分考虑各类边界情况,才能构建出一个可靠的系统。

此外,这次实践让我体会到选择数据结构的影响。TreeMap 虽然可以自动排序,但在特定情况下,使用 HashMap 可能更为高效,这提醒我在实际开发中,数据结构的选择要根据实际需求权衡。

总的来说,这次练习不仅让我提升了代码实现的技能,还加深了我对OOP思想和数据处理的理解。面向对象设计并不是为了追求复杂,而是为了将复杂问题简化为一系列可控的小问题,通过规范和合理的设计,才能实现一个健壮、可扩展的系统。
2. 题目2的采坑总结
问题:

  • 试卷总分不为 100 分
    当试卷中所有题目的分值总和不等于 100 时,需要输出警告信息。
    例如:alert: full score of test paper1 is not 100 points
    答案错误/不正确匹配

  • 用户答卷的答案与正确答案不符时,系统需要在输出中显示错误标识。
    例如:1+1=5false 表示用户答案为 5,但正确答案不是 5。
    试卷中题目的顺序与题号不一致

  • 用户提供的题目顺序与题号顺序不一致时,系统需要根据题号正确关联题目与答案。
    系统应根据题号在试卷和答卷中对齐题目顺序,确保评分和显示的正确性。
    输入数据乱序

  • 题目、试卷、答卷等输入顺序不固定,需要代码处理不同顺序的输入,解析后正确组织数据。
    代码应能够解析乱序的输入,并将题目、分值、答案按题号和试卷编号关联。
    多份答卷的处理

  • 系统应支持对多份答卷的评分和输出,并在每份答卷中逐一显示题目、用户答案、正确性和分数。
    例如在输入样例6中,有两份答卷,需要分别显示各自的评分结果。
    缺失题目或答案

  • 当答卷缺少题目或答案时,系统应输出 answer is null 或其他提示信息以表示未作答情况。
    例如:answer is null 表示用户未回答该题。
    试卷编号无效

  • 当答卷的试卷编号在系统中不存在时,应输出提示信息。
    例如:The test paper number does not exist 提示用户的答卷对应试卷不存在。

心得:在开发考试系统的过程中,通过全面分析各种可能的错误场景,加深了对健壮性设计与异常处理重要性的理解。项目中处理了多个复杂情况,包括试卷满分不等于 100 的验证、题目和答卷顺序的错位处理、乱序输入数据的解析、多份答卷的支持、以及针对缺失题目或答案的提示反馈等。每种异常情况都通过清晰的提示信息反馈给用户,例如“alert: full score of test paper1 is not 100 points”等,为用户提供了友好的错误指引。尤其在乱序输入和多份答卷的处理上,锻炼了在代码设计中实现灵活性与可扩展性的能力。

这些细致的错误处理措施不仅增强了系统的容错性,还能帮助用户快速识别并纠正输入错误,带来更流畅的使用体验。此次项目体会到,提前预见和规划异常情况,在需求分析阶段尽可能覆盖所有边界情境,对于系统的稳定性和可靠性至关重要。整体开发中对细节的关注与应对突发输入情况的准备,让我对编写更健壮和人性化的代码有了更深刻的认识。
3. 题目3的采坑总结
问题:
解析每一行的输入时,应该灵活使用split语句对输入进行拆分,存储,之后在对每一部分的存储进行一一匹配,最后将匹配的结果输出,在此过程中最应该注意的是拆分的逻辑顺序,如何将一行字符串中我们需要的那一部分给提取出来。
以下为其中拆分答卷信息时的代码逻辑

点击查看代码
else if (studentMatcher.matches()) {
                try {
                    String[] studentInfo = studentMatcher.group(1).split("-");
                    for (String info : studentInfo) {
                        String[] parts = info.split(" ");
                        String id = parts[0];
                        String name = parts[1];
                        students.put(id, new Student(id, name));
                    }
                } catch (Exception e) {
                    System.out.println("wrong format:" + input);
                }
            }
当输入格式与期望的不一致时(例如有多余的空格或特殊字符),直接拆分会导致数据解析出错。如"123 John "这样的输入包含额外空格,使用split(" ")可能导致空字符串被解析,parts数组包含空值,影响到后续解析。使用trim()清除多余空格,并在分隔之前验证输入的格式。例如,可以在解析前移除不必要的空白字符。
点击查看代码
String trimmedInfo = info.trim();  // 去除开头和结尾的多余空格
String[] parts = trimmedInfo.split(" ");
if (parts.length == 2 && !parts[0].isEmpty() && !parts[1].isEmpty()) {
    String id = parts[0];
    String name = parts[1];
    students.put(id, new Student(id, name));
} else {
    System.out.println("Incorrect format or missing data: " + info);
}

(2) 心得: 在解析和拆分输入数据的过程中,代码的健壮性和灵活性尤为重要,因为输入数据的格式常常不可控,可能包含格式错误或缺失内容。通过正则表达式或匹配器进行格式验证是首要步骤,能够在解析前过滤掉不符合预期的数据,从源头上减少异常情况的出现。同时,针对数组越界的问题,在访问拆分结果数组之前应始终检查数组的长度,以确保访问到的元素存在,从而避免`ArrayIndexOutOfBoundsException`异常。最后,输入中往往存在多余空白或特殊字符,若直接进行拆分可能会导致意料之外的数据片段,通过使用`trim()`去除空白并进行格式验证,可以有效提高解析的准确性,增强代码的鲁棒性与容错性。这些细节不仅提高了代码的健壮性,也减少了因输入不规范导致的潜在错误。

四、改进建议

  1. 使用接口和抽象类,提升代码的灵活性和扩展性,使得系统更易于增加新的题目类型或功能。
    通过为题目设计一个 Question 接口或抽象类,能够规范所有题目类必须具备的基本功能,如获取题号和题目内容、检查答案等。接口可以简化系统在面临题目扩展需求时的开发难度。
    比如,系统目前可能仅支持单一类型的题目,但如果需要扩展为支持选择题、填空题或编程题等,这种设计就能极大减少修改原有代码的风险。每种题目类型只需实现 Question 接口的基本方法,同时可以扩展特有的方法(例如选择题可添加选项列表),从而保持灵活性。
  2. 分离判分逻辑,通过将评分逻辑从试卷或答题卡类中分离,提升代码的关注点分离度,使评分系统更加灵活和可配置。
    判分逻辑的复杂性较高,涉及到不同题型的评分方式、评分策略(如是否按题型加权)等。将评分相关方法从 ExamPaper 或 AnswerSheet 中分离出来,可以避免将过多功能集中在一个类中,导致代码臃肿且难以维护。同时,通过集中管理评分规则,Grader 类还可以实现多种评分策略(如按百分比评分、分数加权等),便于后续扩展。
    评分分离后,还可以设计评分策略接口 GradingStrategy,实现不同的评分规则。例如,选择题采用标准评分,而填空题可以基于相似度评分,这种设计让系统更加灵活和可配置。
  3. 加强数据验证和异常处理,提升系统的健壮性,避免输入数据不合法或系统运行中断的情况。
    数据验证和异常处理是确保系统稳定性的重要措施。由于系统涉及到题目编号、答案匹配等操作,如果输入数据不符合预期,可能导致意外的错误。因此,在题目录入、答题检查等过程中,需要对输入数据进行严格的验证。通过创建自定义异常类,如 DuplicateQuestionException 或 InvalidAnswerFormatException,能够明确表示不同类型的错误来源,便于调试和错误处理。
    除了在数据录入环节加强验证外,还可以通过异常处理机制捕获系统运行中的意外情况,提供相应的提示或回退处理,以防止程序崩溃。

五、总结

  1. 综合性总结
    在上述三次题目集的编写和完成过程中,逐步提升了对算法复杂度控制和数据结构操作的理解,尤其是在处理解析输入时更加注重代码的健壮性和灵活性。通过不断调试和优化代码,学到了如何更有效地提升程序的效率和鲁棒性。解析输入的过程中,不仅掌握了如何避免数组越界和处理异常输入,同时也通过精细的格式验证提升了代码的稳定性。这一过程也强化了对数据结构的理解,比如数组、字符串处理等基本结构的应用及其优化,同时在设计算法时考虑了复杂度的控制,确保程序在处理大规模数据时依然具备良好的性能。
    对于未来的学习和提升,需要更深入地研究复杂数据结构和算法优化技术,尤其是动态规划和高级图论算法,这些算法在解决复杂问题时具有极高的效率和灵活性。除此之外,编码风格的规范化、详细的文档撰写以及完善的代码测试也是必不可少的方面,它们有助于提升代码的可维护性和可读性,从而减少潜在的错误并提高开发效率。综上所述,这一系列的学习不仅强化了算法和数据结构的应用能力,也为今后的代码优化和大型项目开发奠定了坚实的基础。
  2. 对课程与教师的建议
    对于课程方面的建议,我认为可以加入更多实际案例,特别是涉及复杂算法的内容。一些复杂的算法在实际应用中很常见,但理解起来不容易,如果能有更多贴近现实的例子。此外,课程内容的难度如果能按照“基础—进阶—高级”的顺序来设置,我们可以更清楚地看到每个知识点的前后联系,帮助我们更好地掌握知识。希望课程也能涵盖代码优化、性能调试等方面的内容,因为在面对大量数据时,代码的运行效率非常重要,提前学会这些技能对我们未来的实际编程工作会有很大帮助。
    在教学方式上,建议老师在讲课时可以更多使用具体例子来解释复杂概念。对于算法类知识,单纯的理论讲解可能不太好理解,如果能结合实际代码演示和应用场景,会更容易让人理解算法的用途和效果。比如,可以带着我们一步步解决一个问题,从初始思路到算法选择,再到如何优化,整个过程都详细展示。希望老师在课上能增加一些互动环节,比如提问讨论或分组练习,这样我们可以有更多机会去消化知识,同时也能在实践中发现自己的薄弱点。另外,建议在课程里增加答疑时间,方便我们遇到难题时能及时得到帮助,不至于越积越多。
    最后,建议老师多分享一些关于编程规范和项目经验,比如如何写出清晰的代码、如何注释或如何分模块组织代码。虽然这些细节看似简单,但其实对代码的可读性、维护性有很大影响。通过了解这些标准和技巧,我们可以逐步培养良好的编程习惯,也能更好地适应团队协作的需求。
posted @ 2024-10-26 15:51  千世绪川  阅读(41)  评论(0)    收藏  举报