寒假作业(2/2)——疫情统计
作业描述
问题 | 内容 |
---|---|
这个作业属于哪个课程 | 2020春丨W班 |
这个作业要求在哪里 | 寒假作业(2/2) |
这个作业的目标 | 完成疫情统计的程序以及博客 |
作业正文 | 寒假作业(2/2)——疫情统计 |
其他参考文献 | ... |
1.Github仓库地址
本项目使用Java开发
作业仓库地址:疫情统计
学长由于第一次使用GitHub不是很熟悉,刚开始的时候我编写的时候新建了一个新的仓库来编写,任何commit,push操作都在那个仓库完成,最后要pr的时候发现不能提交,才知道是自己理解错了,所以
提交的那份作业里面没有commit记录,如果允许的话我这里贴一份旧的仓库链接,需要看commit记录的话可以看这个仓库的记录,两份的代码是一样的。
旧仓库:有commit记录的库
2.PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟)| 实际耗时(分钟)
| :-----| :----| :-----| :----| :-----| :---- |
| Planning | 计划 | 30 | 40
| Estimate | 估计这个任务需要多少时间 | 720 | 900
| Development | 开发 | 600 | 720
| Analysis | 需求分析(包括学习新技术) | 60 | 120
| Design Spec | 生成设计文档 | 30 | 30
| Design Review | 设计复审 | 30 | 60
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 30
| Design | 具体设计 | 60 | 120
| Coding | 具体编码 | 480 | 540
| Code Review | 代码复审 | 60 | 50
| Test | 测试(自我测试,修改代码,提交修改) | 120 | 180
| Reporting | 报告 | 120 | 150
| Test Report | 测试报告 | 60 | 120
| Size Measurement | 计算工作量 | 30 | 10
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30
| 合计 | | 2460 | 3100
3.解题思路
1.命令行输入命令的接收与保存
1.刚看到题目的时候,想的比较简单,使用" "空格符号来分割传入的命令即可,但是后面仔细一想,有的命令有多个参数仅仅依靠空格符并不能很好的实现,最后决定先依靠"-"符号分割,分割结束后依靠"
"再次分割处理得到传入的命令。
2.为了保存命令,声明了一个命令类(class command)该类用于保存命令跟命令后带的参数,同时也进行命令跟命令参数的格式检查。
2.日志文件的读取
1.判断日志文件路径是否正确。
2.声明一个省份类对象数组(class province)用于保存各个省份的数据。
3.根据题目要求日志文件内容的格式仅有8种。
<省> 新增 感染患者 n人
<省> 新增 疑似患者 n人
<省1> 感染患者 流入 <省2> n人
<省1> 疑似患者 流入 <省2> n人
<省> 死亡 n人
<省> 治愈 n人
<省> 疑似患者 确诊感染 n人
<省> 排除 疑似患者 n人
便考虑到使用正则表达式去匹配每一行的数据,若命中跳转分支去抓取省份名称跟人数进行处理。
4.按照正则表达式抓取的数据修改province数组中的相应位置的数据。
3.结果的输出
1.判断结果输出路径是否正确
2.查看是否有特定输出要求(-province,-type是否的指定)
3.输出相应结果到指定的文件中
在画这个图片的时候,发现了判断输入/输出路径最好应该在判断命令格式跟命令是一起判断,这样如果有误就可以直接结束程序,不在浪费系统资源,若有修改将放在下面代码优化部分。
4.设计实现过程
1.命令类(class command)
//命令类
//list:判断是否输入-list
//log:判断是否输入-log
//out:判断是否输入-out
//date:判断是否输入-date
//type:判断是否输入-type
//province:判断是否输入-province
//dateContent:-date命令后带参数
//logContent:-log命令后带参数
//outContent:-out命令后带参数
//provinceContent:-province后带参数
//typeContent:-type后带参数
//command:输入的命令字符串数组
class Command{
private Boolean list=false;
private Boolean log=false;
private Boolean out=false;
private Boolean date=false;
private Boolean type=false;
private Boolean province=false;
private String dateContent;
private String logContent;
private String outContent;
private List<String> provinceContent = new ArrayList<String>();
private List<String> typeContent = new ArrayList<String>();
private List<String> command = new ArrayList<String>();
......
}
2.省份类
//省份类 用于存储各个全国和各个省份的各种数据
//代码中开辟一个province数组,第0位存放全国,其余省份按排序一次存放
//name:省份的名称
//ip:感染患者数量
//sp:疑似患者数量
//cure:治愈患者数量
//dead:死亡患者数量
//appear:用来判断是否在日志文件中出现该省份
class province
{
private String name;
private int ip;
private int sp;
private int cure;
private int dead;
private boolean appear;
....
}
3.文件操作-读类
//文件操作类-读文件
//path:日志文件的路径,-log后带的参数
//files:该路径下的说有文件路径(绝对路径)
//filesName:该路径下所有文件的名称,用于判断输入的日期是否超出范围(仅名称不带后缀)
//file:文件路径打开的文件夹
//tempList:该路径下的所有文件
//provinceList:省份数组
//templates:用于匹配日志文件内容的正则表达式模板
//maxDate:该路径下的日志文件的最大日期
//minDate:该路径下的日志文件的最小日期
class readFile{
String path;
ArrayList<String> files;
ArrayList<String> filesName;
File file;
File[] tempList;
province [] provinceList;
String [] templates = {
"(\\S+) 新增 感染患者 (\\d+)人","(\\S+) 新增 疑似患者 (\\d+)人","(\\S+) 感染患者 流入 (\\S+) (\\d+)人",
"(\\S+) 疑似患者 流入 (\\S+) (\\d+)人","(\\S+) 死亡 (\\d+)人","(\\S+) 治愈 (\\d+)人",
"(\\S+) 疑似患者 确诊感染 (\\d+)人",
"(\\S+) 排除 疑似患者 (\\d+)人"
};
String maxDate;
String minDate;
...
}
4.文件操作-写类
//文件操作类-写文件
//provinceList:全国和各个省份的数据统计数组
//isProvince:命令行是否接收-province命令 如果有 isProvince=true反之false
//provinceContent:-province命令后带的参数
//isType:命令行是否接收-type命令 值同isProvince
//typeContent:-type命令后带的参数
//file:输出结果文件
class writeFile
{
private province [] provinceList;
private boolean isProvince;
private List<String> provinceContent;
private boolean isType;
private List<String> typeContent;
private File file;
...
}
5.代码说明
看了下自己的代码,好像发现没什么值得展示的,都是一些比较平常的代码,也没有难以理解,下面就解释一下一些稍微难以理解的代码(为了偷懒写的代码)
代码的具体解释写在来各个代码块的开头的注释和代码旁边的注释中
//判单读取日志文件数量
//传入参数:日期 如:2020-01-22
//返回值:false 或 true
//path:-date命令后面带的日期
//path有两种取值:1.正常日期 ,输入-date后带的符合规范的日期。
// 2. “all” 字符串,未输入-date命令或者输入-date命令后未指定具体日期时
// 为了偷懒默认日期就为all,仅当有输入-date命名且输入指定日期后才更新
public boolean readLog(String path)
{
if(path.equals("all")) //如果path是all直接读取到maxDate日期为止
{
readLogFile(maxDate);
return true;
}
else
{
if(path.compareTo(maxDate)>0||path.compareTo(minDate)<0)//判断输入的日期是否在日志文件的
{ //范围中
return false;
}
else
{
readLogFile(path);
return true;
}
}
}
//输入结果到文件方法
//没有想到什么好的解决办法,就把每种情况都列了出来
//isProvince=true这代表输入了-province命令,反之没有
//isType=true这代表输入了-type命令,反之没有
//按题目要求输出有四种不同的情况
//1.没输入-province命令,没输入-type
//2.输入-province命令,没输入-type
//3.输入-province命令,输入-type
//4.没输入-province命令,输入-type
//分别与下面的四个判断对应
//由于嵌套循环较多,若程序性能较差可以考虑修改这方面的代码(虽然我已经想过了)
//因为嵌套循环跟判断较多具体代码就不贴了,详细可以看代码,这理解解释下这四个判断的作用
if(isProvince==false&&isType==false){...}
if(isProvince==true&&isType==false){...}
if(isProvince==true&&isType==true){...}
if(isProvince==false&&isType==true){...}
//判断各命令参数是否合法
//输入参数:无
//返回值:true或false
//-list必不可少,-date可有可无 日期格式(yyyy-mm-dd)缺一不可
//-log命名跟后带参数均不可少
//-out命名跟后带参数均不可少
//本来还应该-province后面的参数只能是“全国或各个省份名称”,但是由于偷懒就没写了。
//看作业要求好像测试的时候也不会出现这样的情况,就算出现了代码也能正常运行不会异常终止罢了😂
public boolean isLegal()
{
if(!list)
{
System.out.println("-list命令缺失");
return false;
}
if(date)
{
String regex = "[0-9]{4}-[0-9]{2}-[0-9]{2}";//这段代码的作用是为了保证必须满足(yyyy-mm-dd)反例:如(2020-1-2)也是错误的
Pattern pattern = Pattern.compile(regex);//为什么写它是因为好像java自带的日期格式判断会将上述反例判断为正确,顾添加了一段代码
Matcher m = pattern.matcher(dateContent);
boolean dateFlag = m.matches();
if (!dateFlag) {
System.out.println("日期格式错误");
return false;//日期格式错误 例如:2020-1-3(正确为2020-01-03)
}
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
formatter.setLenient(false);
try{
formatter.parse(dateContent);
}catch(Exception e){
System.out.println("日期格式错误!");
return false;//日期格式错误 例如:2a20-01-03(出现非数字字符)
}
}
if(log)//输入了-log命令
{
if(logContent==null)//logContent为-log命令后面后带的参数
{
System.out.println("-log命名参数缺失!");
return false;//输入-log命令 却未输入参数
}
}
else
{
System.out.println("缺失-log命令!");
return false;//缺少-log命令
}
if(out)
{
if(outContent==null)
{
System.out.println("-out命令参数缺失!");
return false;//输入-out命令 却未输入参数
}
}
else
{
System.out.println("缺失-out命令!");
return false;//缺失-out命令
}
if(type)
{
if(typeContent==null)
{
System.out.println("-typy命令参数缺失!");
return false;//输入-type 命令 却不输入参数
}
else
{
for(int i=0;i<typeContent.size();i++)
{
if(!typeContent.get(i).equals("sp")&&!typeContent.get(i).equals("ip")
&&!typeContent.get(i).equals("cure")&&!typeContent.get(i).equals("dead"))
{
System.out.println("-type命令参数错误!");
return false;//type的参数不是(ip sp cure dead四种之一)
}
}
}
}
if(province)
{
if(provinceContent==null)
{
return false;//输入 -province命令却不输入参数
}
}
return true;
}
6.单元测试截图和描述
测试日志文件日期:
测试日志文件内容:
测试结果如下:
(1)输入命名 list -log C:\log\ -out C:\result\ListOut1.txt -date 2020-01-22
(2)输入命令 list -log C:\log\ -out C:\result\ListOut2.txt -date 2020-01-22 -province 福建 河北
(3)输入命令 list -log C:\log\ -out C:\result\ListOut7.txt -date 2020-01-23 -type cure dead ip -province 全国 浙江 福建
(4)输入命令 list -log C:\log\ -out C:\result\ListOut.txt (无-date命令,统计全部结果)
(5) 输入命令 list -log C:\log\ -out C:\result\ListOut.txt -date 2020-03-22 (日期超出范围)
(6) 输入命令 list -log C:\log\ -out C:\result\ListOut.txt -date 2020-01-a2 (日期格式错误)
(7) 输入命令 list -log C:\log\ -out C:\result\ListOut.txt -type aa (type命令参数错误)
(8) 输入命令 list -log D:\log\ -out C:\result\ListOut.txt (日志文件路径错误,电脑不存在D盘)
(9) 输入命令 list -log C:\log\ -out D:\result\ListOut.txt (输出文件路径错误,电脑不存在D盘)
(10) 输入命令 list -out D:\result\ListOut.txt (缺失-log命令)
(11) 输入命令 list -log -out D:\result\ListOut.txt (缺失-log命令后带参数)
7.单元测试覆盖优化和性能测试
单元测试覆盖率代码:
测试命令:list -log C:\log -out C:\result\ListOut7.txt -date 2020-01-27
结果:
分析:
1.Command覆盖率较低是由于命令并未完全输入 未输入-province等命令导致分支并未跑到,同时其中还包含命令正确性判断模块。
2.writeFile类覆盖率低但接近预期值,这是由于输出模块为四个判断分支,只选取其中一段分支运行故接近25%
性能测试结果:
分析:
1.输出模块中for循环嵌套较多,性能较差。
2.分支判断过多导致一些分支执行的次数较少。
3.性能优化暂无办法,写的时候就已经考虑过了。
8.代码规范
9.心路历程与收获
1.通过这次作业,了解到了Java的单元测试跟单元测试覆盖率还有性能测试,这是我认为通过这次作业最大的收获,之前写代码都是写完即可并没有去考虑这些。
2.作业也让我重新复习了一遍Java的各种语法跟使用,对java有了更深的了解。
3.这次作业也让我们规范了自己的编程风格,这是在之前的日子从未有过的导致自己写出来的代码有时候自己都看不懂,通过代码规范让自己的代码更加的易懂。
4.同时发现自己过于心急,并没有拿到手上并没有非常好的进行需求分析,一到手就开始编写,导致很多东西在编写的过程中改来改去,这一点非常不好以后要认认真真的进行需求分析。
5.学习了GitHub的使用,之前老觉得这些东西没什么好的,自己写就是了,用了之后发现真香。
6.认清了自己的位置,对于成为一名合格的程序员还有很长的路要走
10.技术路线图相关的5个仓库
名称 | 链接 | 简介 |
---|---|---|
RxJava | RxJava | JAVA的一种异步框架,使用可观测的序列来组成异步的,基于事件的程序的库 |
RxAndroid | RxAndroid | RxAndroid是专供Android平台的RxJava |
Android布局 | Android布局 | 一些Android布局教材跟例子 |
Android学习笔记 | Android学习笔记 | 由国内知名博主编写的Android入门教材 |
《第一行代码》中天气案例 | 《第一行代码》中天气案例 | 《第一行代码》中的天气预报的例子加改写 |