第一次blog作业

前言:

1. 第一次大作业
(1) 知识点:类和对象的使用,一维数组,多维数组,字符串处理(StringTokenize、equals、contains等)。
(2) 题量: 5题。
(3) 难度(1-10分)4分

2. 第二次大作业
(1) 知识点:类和对象的使用,ArrayList,一维数组,多维数组,字符串处理(StringTokenize、equals、contains等)。
(2) 题量: 4题。
(3) 难度(1-10分):6分

3. 第三次大作业
(1) 知识点:类和对象的使用,正则表达式,ArrayList,一维数组,多维数组,字符串处理(StringTokenize、equals、contains等)。
(2) 题量: 3题.
(3) 难度(1-10分):9分

设计与分析:

1,第一次大作业

类图:

题目是设计实现答题程序,模拟一个小型的测试,要求输入题目信息和答题信息,根据输入题目信息中的标准答案判断答题的结果。
因为这个学期才开始接触面向对象和Java,第一次大作业把所有试卷内容的处理放在了一个类里面,以面向过程的思路解决问题,好在题目简单,一个类可以轻松解决这个题目且不会显得繁杂。
第一次大作业最后一题代码SourceMontor的生成报表内容:

总行数(Lines):82;
语句数目(Statements):57;
函数圈复杂度(Function Complexity):10;
Max Depth:5;
Maximum Complexity:10;
其他略。

2, 第二次大作业

类图:

该题在第一次大作业最后一题的基础上增补或者修改了一些内容,从类图上就可以看出比第一次麻烦了很多,该题除了Main外有三个类,Questions类处理题目数据,Papers存储题目序号,对应分数,将其整合成一张卷子,PaperAnswers类处理Questions对象和Papers对象的信息,信息的处理部分由Main解决,它负责处理输入信息,并把这些信息喂给其他三个类,只有一个main(),忙滴很。
第二次大作业最后一题代码SourceMontor的生成报表内容:

总行数(Lines):261;
语句数目(Statements):171;
函数圈复杂度(Function Complexity):23;
Max Depth:8;
Maximum Complexity:23;
其他略。
圈复杂度主要靠main(),一个函数干的事情太多,if加for的嵌套使其变得很复杂。

3, 第三次大作业

类图:

该题依前一次大作业最后一题的基础上增补或者修改了一些内容,除了之前的那几个,本次增加了一个Students类,解决学生信息,大体设计思路与第二项差不多,就是加了些东西,以及根据题目的变化改了一些处理方法。
第三次大作业最后一题代码SourceMontor的生成报表内容:

总行数(Lines):372;
语句数目(Statements):249;
函数圈复杂度(Function Complexity):33;
Max Depth:8;
Maximum Complexity:33;
其他略。
因为题目的难度加大,Main里面的main()变得越来越复杂,圈复杂度也越来越高,我也终于反应过来,Main里面可以加一些其他方法,不是所有工作都放在main()里面,完全可以加一些其他方法来处理信息,不过反应过来已经有点晚了,时间不允许,下次一定。

踩坑心得:

第一次大作业踩坑和心得:

(1) 误读回车
Scanner input=new Scanner(System.in);
int n=input.nextInt();
Exam[] exams=new Exam[n];
while(true){
String ch=input.nextLine();
if(ch.equals("end"))
break;
。。。。。。。。。。。。
}
}
输入:
2 #N:1 #Q:1+1= #A:2 #N:2 #Q:2+2= #A:4 #A:2 #A:2 end
测试结果:
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
at Main.main(Main.java:35)
(非零返回)
正确结果:
1+1=~2 2+2=~2 true false
原因:
在键盘输入n后回车被后面的ch接收,导致程序非零返回。
解决方法:

    Scanner input=new Scanner(System.in);
    int n=input.nextInt();
    Exam[] exams=new Exam[n];
    String chs=input.nextLine();//处理回车

    while(true){
        String ch=input.nextLine();
        if(ch.equals("end"))
        	break;
		。。。。。。。。。。。。
        }
    }

中间添加一个chs接收回车信息。
(2) 首尾空格的处理
输入:
1
//#N:1 #Q: The starting point of the Long March is #A:ruijin
//#A:ruijin
End
正确结果:
The starting point of the Long March is~ruijin
True
未改前代码:
String tms=input.nextLine();
char[] tmss=tms.toCharArray();
while(tmss[j+2]' ')
j=j+1;
while(tmss[length-i]
' ')
i=i+1;
结果:编译错误。
改后代码:
Tms= Tms.trim()
结果:
The starting point of the Long March is~ruijin
True
理论上将字符串用toCharArray转化成字符数组,在检测字符数组的首尾是否有空格并对其进行处理,这应该是可行的,可能因为我水平不行,一直出错。最后还是看博客看到了trim()方法,直接去掉字符串首尾的空格。
心得:第一点就是在输入字符内容的时候注意回车的问题,第二就是对于Java的初学者来说,多看多学很重要,Java有很多现成的方法,了解更多的方法可以帮你快速的解决问题,可以避免出现你写了半天代码后发现有现成的方法可以一行解决问题这一情况的出现,可以不会但得知道。

第二次大作业踩坑和心得:

(1)Integer.parseInt()字符串转数字出现问题
StringTokenizer st = new StringTokenizer(ch,"#SA:");
String c=st.nextToken();//创建答卷
int m=Integer.parseInt(c);
在使用StringTokenizer切割字符串时出现字符串内存在空格的问题,导致Integer.parseInt()字符串转数字时出错。
本题未出现题号、分数出现错误输入非数字的情况,故我只添加了一个trim()处理首尾空格便解决了问题,但最好使用正则表达式处理,可以更好的保证数据的正确。

(2) 结果输出顺序出现问题:
源码:

public class Main{
public static void main(String[] args){
int I=0,J=0;
Scanner input=new Scanner(System.in);
ArrayList questions = new ArrayList();
Papers[] paper=new Papers[10];
。。。。。。。
for(int i=0;i<J;i++)//最后输出部分
{
if(paperAnswer[i].getallscore()!=100)
System.out.println("alert: full score of test paper"+paperAnswer[i].getNum()+" is not 100 points");
for(int j=0;j<paperAnswer[i].getLength();j++)
{
System.out.println(paperAnswer[i].ToString(j));
}
paperAnswer[i].FinalScore();
}
}
}
输入:
\#N:3 #Q:3+2= #A:5
\#N:2 #Q:2+2= #A:4
\#T:1 3-7 2-6
\#S:1 #A:5 #A:22
\#N:1 #Q:1+1= #A:2
\#T:2 2-5 1-3 3-2
\#S:2 #A:5 #A:4
End
输出:
alert: full score of test paper1 is not 100 points
3+2=5true
2+2=22false
7 0~7
alert: full score of test paper2 is not 100 points
2+2=5false
1+1=4false
nullnullfalse
0 0 2~2
正确输出:
alert: full score of test paper1 is not 100 points
alert: full score of test paper2 is not 100 points
3+2=5true
2+2=22false
7 0~7
2+2=5false
1+1=4false
answer is null
0 0 0~0
在本题我将所有的输出放在了main里面,不仅使main复杂化,同时不易理清思路,alert: full score of test paper1 is not 100 points本因在创建试卷类的对象时输出,但在写代码时我将所有内容放在main里一起输出,一部分原因是因为自己审题的问题,另一部分还是对类的作用理解不到位,main干了太多其他类应该干的事

第三次大作业踩坑和心得:

(1)对于大量不同字符串信息处理
for(int i=0;;i++)

    {
        P[i]=input.nextLine();
        if(P[i].equals("end"))
        	break;
        length++;
    }
    for(int k=0;k<length;k++)
    {
        String ch=P[k];
        if(ch.contains("#Q:"))
        {
        	String[] c=new String[3];
        	StringTokenizer st = new StringTokenizer(ch,"#ANQ:");//切割字符串
        	int i=0;
        	while(i<3)
       		 {
       			 c[i]= st.nextToken();
       			 c[i]=c[i].trim();//去掉首尾空格
       			 i++;
       		 }
        	int m=Integer.parseInt(c[0]);//字符串转数字
        	questions.add(new Questions(m,c[1],c[2]));
        }
        if(ch.contains("#X:"))
        {
        	String regStr="\\d+ ([a-z]|[A-Z])+";
    		Pattern pattern = Pattern.compile(regStr);
            Matcher matcher = pattern.matcher(ch);
            while(matcher.find()) {
            	students.add(new Student(matcher.group(0)));
            }
        }
    }
    for(int k=0;k<length;k++)
    {
        String ch=P[k];
        if(ch.contains("#T:"))
        {
        	StringTokenizer st = new StringTokenizer(ch," ");//切割字符串
        	String c=st.nextToken();
        	char cc=c.charAt(3);//提取试卷号
        	String ccc=cc+"";
        	int m=Integer.parseInt(ccc);
        	paper[I]=new Papers(m);
        	while(st.hasMoreElements())
        	{
        		c=st.nextToken();
        		StringTokenizer st1 = new StringTokenizer(c,"-");
        		String c1=st1.nextToken();
        		m=Integer.parseInt(c1);
        		paper[I].addQuestions(m);
        		c1=st1.nextToken();
        		m=Integer.parseInt(c1);
        		paper[I].setScore(m);
        	}
            if(paper[I].getallscore()!=100)
                System.out.println("alert: full score of test paper"+paper[I].getNum()+" is not 100 points");
        	I++;
        }
    }
    for(int k=0;k<length;k++)
    {
        String ch=P[k];
        if(ch.contains("#S:"))
        {
        	StringTokenizer st = new StringTokenizer(ch,"#SA:");
        	String c=st.nextToken();//创建答卷
        	String regStr="(?<a>\\d+)+ \\d+";//读取学号
    		Pattern pattern = Pattern.compile(regStr);
            Matcher matcher = pattern.matcher(c);
            int m=0;
            while(matcher.find()) {
            	m=Integer.parseInt(matcher.group("a"));
            }
            boolean flag=false;
       }

}
这是原字符串处理的方式,使用contains 找到对应字符串,再用StringTokenizer一点一点切割字符串,多次if嵌套导致很容易出错,并且代码可读性低,出错时很难发现问题出现的位置,并且就算发现了也难以修改。
使用正则表达式后的代码:
String NN=" *#N: (?.) *#Q: (?.) *#A: (?.)";
String TT=" *#T: *(?
\d+) *( \d+-\d+ *)+";
String XX=" *#X: *";
String SS=" *#S: *(?
\d+) *(?\d+)( #A:\d+-\d )";
String DD=" #D:( N - \d+ )+ ";
while(true)
{
String ch=input.nextLine();
boolean flag=false;
if(ch.equals("end"))
break;
Pattern pattern;
Matcher matcher;
pattern = Pattern.compile(NN);
matcher = pattern.matcher(ch);
while(matcher.find())
{
questions.add(new Questions(matcher.group("a"),matcher.group("b"),matcher.group("c")));
flag=true;
}
。。。。。
If和for的嵌套明显变少了,比如对question信息的处理,未修改前代码使用了if,while两层嵌套,代码十四行,而使用正则表达式没有进行嵌套并且相关代码只有五行(Pattern pattern;Matcher matcher;这俩声明未算上,应为后面的都会用上)。
在处理多种字符串信息的时候最好还是用正则表达式,可以减少代码的复杂度。
(2)输入信息间的空格的处理:
修改前:
String NN="#N:(?
.)#Q:(?.)#A:(?.)";
String TT="#T:(?
\d+)( \d+-\d+)";
String XX="#X:";
String SS="#S:(?
\d+) (?\d+)( #A:\d+-\d+)";
String DD="#D:(N-\d+)";
修改后:
String NN=" *#N: (?
.) *#Q: (?.) *#A: (?.)";
String TT=" *#T: *(?
\d+) *( \d+-\d+ *)+";
String XX=" *#X: *";
String SS=" *#S: *(?
\d+) *(?\d+)( #A:\d+-\d )";
String DD=" *#D:( *N *- *\d+ *)+ ";
其实就是在字符串间添加了 (空格),
是指0或多个对应字符,未修改前因为没有 *,一旦输入内容多了一个空格就会导致无法找到。
总而言之,熟练使用正则表达式可以很好的帮助你解决问题。

改进建议:

对于第一次大作业:
(1) 代码缺乏注释,建议为重要的部分添加注释,以提高代码的可读性和可维护性。
(2) StringTokenizer 类是较旧的,应使用 String 类的 split 方法来分割字符串。更复杂的用正则表达式。
对于第二次大作业:
(1) 代码缺乏注释,建议为重要的部分添加注释,以提高代码的可读性和可维护性。
(2) Java中的变量命名通常使用驼峰命名法,并且变量名应该具有描述性。例如,I 和 J 应该被替换为更具描述性的名称,如 questionIndex 和 paperIndex。
(3) 用正则表达式可以更好的处理本题的信息。
(4) 考虑将输入解析和处理的逻辑分离到不同的方法中,以提高代码的可读性和可维护性。
对于第二次大作业:

(1) 代码缺乏注释,建议为重要的部分添加注释,以提高代码的可读性和可维护性。
(2) 您为部分循环重新编译了相同的正则表达式,这是不必要的。可以将正则表达式的编译移到循环外部,只编译一次。
(3) 如果试卷中的问题和分数数量是不确定的,那么使用 ArrayList 或其他集合类型可能比固定大小的数组 Papers[] 更合适
(4) 当前代码首先读取所有输入行到数组 P 中,然后再处理这些行。这可能导致不必要的内存使用。可以考虑直接处理输入,而不是先存储到数组中。
(5) 可以将输入处理、问题解析和试卷解析的逻辑分别放在不同的方法中,而不是全放在main()里面。

总结:

通过完成这三次Java编程作业,我加深了对面向对象的理解,学会正则表达式,ArrayList的简单使用,同时了解到了许多java自带的方法(trim,equals等)
目前我认为我需要进一步学习和研究的地方一是加强面向对象的设计而不是面向过程设计,二就是多了解一些Java方法。

posted @   Gaadwd  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示