作業描述
問題 | 內容 |
---|---|
這個作業屬於哪個課程 | 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入門教材 |
《第一行代碼》中天氣案例 | 《第一行代碼》中天氣案例 | 《第一行代碼》中的天氣預報的例子加改寫 |