軟工實踐寒假作業(2/2)疫情統計程序

這個作業屬於哪個課程 2020春|S班(福州大學)
這個作業要求在哪裏 作業要求
這個作業的目標 設計、開發一個疫情統計的程序、學習對程序的優化、學習GitHub的使用、PSP(個人軟件開發流程)的學習使用、《構建之法》的學習
作業正文 https:////www.cnblogs.com/hhhqqq/p/12306200.html
其他參考文獻 幾篇博客教程:GitHub|.gitignore|github desktop|fork、pr|JUnit4單元測試|性能分析|...

GitHub倉庫地址

<a href = "https://github.com/904566722/InfectStatistic-main" target="_blank">https://github.com/904566722/InfectStatistic-main</a>

《構建之法》1~3章學習&PSP表格

學習記錄

學習筆記:<a href="https://www.cnblogs.com/hhhqqq/p/12287911.html" target="_blank">https://www.cnblogs.com/hhhqqq/p/12287911.html</a>

PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(min) 實際耗時(min)
Planning 計劃 60 50
Estimate 估計這個任務需要多少時間 10 15
Development 開發 760 735
Analysis 需求分析 (包括學習新技術) 180 200
Design Spec 生成設計文檔 20 30
Design Review 設計複審 10 10
Coding Standard 代碼規範 (爲目前的開發制定合適的規範) 40 30
Design 具體設計 60 90
Coding 具體編碼 300 290
Code Review 代碼複審 30 25
Test 測試(自我測試,修改代碼,提交修改) 120 60
Reporting 報告 90 150
Test Report 測試報告 15 10
Size Measurement 計算工作量 10 20
Postmortem & Process Improvement Plan 事後總結, 並提出過程改進計劃 45 25
total 合計 990 1005

解題思路

對照“疫情統計程序的需求文檔”理清文檔的結構

221701419
    \--src	//源代碼
        InfectStatistic.java
        Lib.java
    \--log	//項目的輸入文本,
        2020-01-22.log.txt
        ...
    \--result	//處理後最終結果的輸出
        ListOut1.txt
        ...

找到合適的數據結構

  • 分析“日誌文本”,需要統計的是每個省的數據,可以創建一個**省類(Province)**來記錄感染患者、疑似患者、治癒等信息
public class Province{
    String provinceName; // 省份名稱
    int ip; // 感染患者
    int sp; // 疑似患者
    int cure; // 治癒
    int dead; // 死亡
    //構造等其他方法
    ...
}
  • 分析“需求”,最終的處理結果要將每個省的信息按行輸出,因此可以將之前參加統計的每個省類加入一個集合,輸出時從該集合中依次取出,並打印結果,我選擇了哈希表(HashTable),將省名作爲鍵,Province作爲值
Province Fujian = new Province();
HashTable<String, Province> hastable = new HashTable<String, Province>(35);
hashtable.put("福建",Fujian);

對日誌文本詳細分析

  • 對log日誌中出現的幾種情況分析,可以用String的**split(" ")**來分割主謂賓

    該日誌中出現的幾種情況 用split分割後的數組長度
    1、<省> 新增 感染患者 n人 4
    2、<省> 新增 疑似患者 n人 4
    3、<省1> 感染患者 流入 <省2> n人 5
    4、<省1> 疑似患者 流入 <省2> n人 5
    5、<省> 死亡 n人 3
    6、<省> 治癒 n人 3
    7、<省> 疑似患者 確診感染 n人 4
    8、<省> 排除 疑似患者 n人 4
    String line = "福建 新增 感染患者 1人";
    String[] afterSplitStrings = line.split(" ");
    //afterSplitStrings[0]:"福建" [1]:"新增" [2]:"感染患者" [3]:"1人"
    

    分類後數組長度的三種情況:3、4、5

  • 分類後可以得到需要修改的省份名稱,兩種情況:1.僅需修改一個省份;2.需修改兩個省份

  • 得到需要修改的省份後判斷需要執行的操作類型,分析日誌中出現的幾種情況思考要如何修改相應省份的數據,並將操作賦予一個類型ID

    日誌出現的情況 數據修改 操作類型ID
    <省> 死亡 n人 死亡數+n && 感染者-n 1
    <省> 治癒 n人 治癒+n && 感染者-n 2
    <省> 新增 感染患者 n人 感染者+n 3
    <省> 新增 疑似患者 n人 疑似者+n 4
    <省> 排除 疑似患者 n人 疑似者-n 5
    <省> 疑似患者 確診感染 n人 疑似者-n && 感染者+n 6
    <省1> 感染患者 流入 <省2> n人 省1 感染者-n && 省2 感染者+n 7
    <省1> 疑似患者 流入 <省2> n人 省1 疑似者-n && 省2 疑似者+n 8

    因此需要:1.Province對數據相應修改的方法

    ​ 2.一個能夠根據省份名稱和操作類型ID執行相應操作的方法

對需求文檔詳細分析

先不考慮命令以及參數的內容,先將日期、輸入目錄、輸出文件作爲常量使用,來完成需求裏要求的功能:

  • 讀取log文件夾裏的文件
  1. 能夠篩選出指定日期前的文件

  2. 忽略註釋行

  • 數據的統計
  1. 省份的統計

從輸入文件讀取一行後進行分析,省份存在以下情況:

只有一個省
    *哈希表中沒有該省
    *哈希表中存在該省
兩個省
	*存在省1,存在省2
	*存在省1,不存在省2
	*不存在省1,存在省2
	*不存在省1,不存在省2
----存在則從hashtable取出,不存在則新建Province類,然後put進hashtable
  1. 全國的統計

所有要求的log日誌文件處理完後,遍歷hashtable來統計全國的數據

  • 輸出到相應目錄,全國總是排第一個,別的省按拼音先後排序,末尾填上一行文檔數據說名和一行命令
輸出示例:
全國 感染患者22人 疑似患者25人 治癒10人 死亡2人
福建 感染患者2人 疑似患者5人 治癒0人 死亡0人
浙江 感染患者3人 疑似患者5人 治癒2人 死亡1人
// 該文檔並非真實數據,僅供測試使用
// 命令: ....

命令行參數

一個命令list,五個參數名**-log、 -out、 -date、 -type、 -province**

示例命令行:

java InfectStatistic list -date 2020-01-22 -log D:/log/ -out D:/output.txt -type sp ip -province 福建
  • 從list開始,其後的參數都存入了args數組,寫個方法從其中提取出參數名,然後再取得相應的參數值

  • 比較需要注意的幾點:

  1. -date 不設置爲默認最新的一天,因此要有一個取得log裏最新時間的方法;傳入的時間超過最新時間給出“日期超出範圍的提示”

  2. -type 與 -province可能攜帶一到多個命令參數,-province指定輸出的省份也要排序,兩者的參數需要作爲參數傳入給寫入文件的方法,對輸出的格式進行規約,可能出現以下四種組合:

1.指定類型 && 指定省份
2.指定類型 && 無指定省份
3.無指定類型 && 指定省份
4.無指定類型 && 無指定省份

設計實現過程

大致流程

graph LR
a[命令行處理]-->b[初始化相應變量]
b-->c[獲得log文件]
c-->d[遍歷log統計數據]
d-->e[打印結果到txt文件]

代碼組織

InfectStatistic的結構:

InfectStatistic{
    public class Province{...}	//省類,用來記錄感染患者、疑似患者、治癒、死亡等信息
    static class ×××Methods{...}	//存儲靜態方法的靜態類,編程過程中根據方法作用的類別歸類
    public static void main(String[] args){}
}
  • 省類Province:
public class Province{
    String provinceName; // 省份名稱
    int ip; // 感染患者
    int sp; // 疑似患者
    int cure; // 治癒
    int dead; // 死亡
    //構造等其他方法
    //屬性的加減
    //輸出屬性信息
    ...
}
  • 根據大致流程將靜態方法大致歸類:

    1. 對傳入的命令行的處理
    2. 取得log文件列表
    3. 統計信息
    4. 哈希表的相關操作
    5. 結果輸出
graph LR
a[InfectStatistic]-->b[Province類]
a-->c[靜態類-命令行處理相關方法]
a-->d[靜態類-取得log文件相關方法]
a-->e[靜態類-統計信息相關方法]
a-->f[靜態類-哈希表操作的相關方法]
a-->g[靜態類-打印結果相關方法]

關鍵函數流程圖

讀入信息,修改省份數據

graph LR
A[一行信息]-->B[分割該字符串</br>得到省份&人數&操作類型]
B-->C{哈希表中是否存在省}
C-->|存在| D[取出該省]
D-->E[修改數據]
C-->|不存在| F[新建並初始化Province實例]
F-->G[存入哈希表]

獲取文件夾下指定日期前的所有文件名

graph TD
a[格式化日期格式]-->b[用目錄下的文件名列表初始化字符串數組]
b-->c[將字符串日期轉爲Date格式]
c-->d{指定的日期與列表中最大日期比較}
d-->|指定日期大於最大日期|e[日期超出範圍提示]
d-->|指定日期小於最大日期|f[遍歷日期字符串數組]
f-->g{與指定日期比較}
g-->|小於等於指定日期|h[加入結果數組]
g-->|大於指定日期|i[無操作]
j[編寫getMaxDate函數</br>獲得最大日期]-->d

輸出文件

graph TD
a[開始]-->b{判斷有無省份參數}
b-->|沒有| e[排序傳入的哈希表]
e-->f[遍歷該哈希表]
f-->g{判斷有無類型參數}
g-->|沒有|h[打印全部信息]
g-->|有|i[打印指定信息]

b-->|有|j[新建哈希表]
j-->k[遍歷指定的省份]
k-->L{判斷傳入的哈希表是否有該省}
L-->|沒有| m[新建並初始化Province實例</br>傳入新的哈希表]
L-->|有| o[從傳入的哈希表取出並傳入新的哈希表]
m-->p[排序新的哈希表]
o-->p

p-->f

關鍵代碼說明

判斷操作類型

/**
 * description:判斷操作類型
 * @param strings 分割後的字符串數組
 * @return 返回值操作類型ID(1~8)
 */
public static int getOperateType(String[] strings) {
    int len = strings.length;
    int res = 0;
    if (len == 3) {
        if (strings[1].equals("死亡")) {
            res = 1;
        } else if (strings[1].equals("治癒")) {
            res = 2;
        }
    } else if (len == 4) {
        if (strings[1].equals("新增")) {
            if (strings[2].equals("感染患者")) {
                res = 3;
            } else if (strings[2].equals("疑似患者")) {
                res = 4;
            }
        } else if (strings[1].equals("排除")) {
            res = 5;
        } else {
            res = 6;
        }
    } else {
        if (strings[1].equals("感染患者")) {
            res = 7;
        } else {
            res = 8;
        }
    }
    return res;
}

解釋思路:

根據讀取的每行信息分割後的數組,其長度只有三種:

  • 3:<省> 死亡 n人<省> 治癒 n人,通過判斷第二個字符串區分操作類型;
  • 4:<省> 新增 感染患者 n人<省> 新增 疑似患者 n人<省> 疑似患者 確診感染 n人<省> 排除 疑似患者 n人,先判斷第二個字符串是“新增”還是“排除”,“新增”裏再判斷第三個字符串是“感染患者”還是“疑似患者”,便可區分四者;
  • 5:<省1> 感染患者 流入 <省2> n人<省1> 疑似患者 流入 <省2> n人,判斷第二個字符即可

統計數據

/**
* description:統計省份數據
* @param lineString 一行字符串
* @param hashtable 保存參與統計的省份
*/
public static void calcProvince(String lineString, Hashtable<String, Province> hashtable) {
    InfectStatistic infectStatistic = new InfectStatistic();
    String[] afterSplitStrings = lineString.split(" ");
    int numAfterSplit = afterSplitStrings.length; // 切割後數量
    int number = OpLineStringMethods.getNumber(afterSplitStrings[numAfterSplit - 1]); // 一行信息中涉及的人數
    String[] provinceNameStrings = OpLineStringMethods.getNeedModifyProvinceNames(afterSplitStrings);   //需要修改數據的省份名稱
    int operateType = OpLineStringMethods.getOperateType(afterSplitStrings);    // 獲得操作類型

    if (provinceNameStrings[1].equals("")) { // 只有一個省
        if (!hashtable.containsKey(provinceNameStrings[0])) { // 哈希表中沒有該省
            Province province = infectStatistic.new Province(provinceNameStrings[0], 0, 0, 0, 0);
            RelativeProviceMethods.executeOperate(province, province, operateType, number);
            hashtable.put(province.getProvinceName(), province);
        } else {
            Province province = hashtable.get(provinceNameStrings[0]);
            RelativeProviceMethods.executeOperate(province, province, operateType, number);
        }
    } else if (!provinceNameStrings[1].equals("")) { // 有兩個省
        Province province1 = null;
        Province province2 = null;
        if (hashtable.containsKey(provinceNameStrings[0]) && hashtable.containsKey(provinceNameStrings[1])) {
            province1 = hashtable.get(provinceNameStrings[0]);
            province2 = hashtable.get(provinceNameStrings[1]);
        } else if (hashtable.containsKey(provinceNameStrings[0])
                   && !hashtable.containsKey(provinceNameStrings[1])) {
            province1 = hashtable.get(provinceNameStrings[0]);
            province2 = infectStatistic.new Province(provinceNameStrings[1], 0, 0, 0, 0);
            hashtable.put(provinceNameStrings[1], province2);
        } else if (!hashtable.containsKey(provinceNameStrings[0])
                   && hashtable.containsKey(provinceNameStrings[1])) {
            province1 = infectStatistic.new Province(provinceNameStrings[0], 0, 0, 0, 0);
            hashtable.put(provinceNameStrings[0], province1);
            province2 = hashtable.get(provinceNameStrings[1]);
        } else if (!hashtable.containsKey(provinceNameStrings[0])
                   && !hashtable.containsKey(provinceNameStrings[1])) {
            province1 = infectStatistic.new Province(provinceNameStrings[0], 0, 0, 0, 0);
            province2 = infectStatistic.new Province(provinceNameStrings[1], 0, 0, 0, 0);
            hashtable.put(provinceNameStrings[0], province1);
            hashtable.put(provinceNameStrings[1], province2);

        }
        RelativeProviceMethods.executeOperate(province1, province2, operateType, number);
    }

}

 /**
 * description:統計全國的數據
 * @param hashtable 保存着所有參與統計的省份
 */
public static void calcWholeNation(Hashtable<String, Province> hashtable) {
    InfectStatistic infectStatistic = new InfectStatistic();
    Province wholeNation = infectStatistic.new Province("全國", 0, 0, 0, 0);
    Set set = hashtable.keySet();
    Iterator iterator = set.iterator();
    while(iterator.hasNext()) {
        Object keyObject = iterator.next();
        wholeNation.ip += hashtable.get(keyObject).getIp();
        wholeNation.sp += hashtable.get(keyObject).getSp();
        wholeNation.cure += hashtable.get(keyObject).getCure();
        wholeNation.dead += hashtable.get(keyObject).getDead();
    }
    hashtable.put("全國", wholeNation);
}

解釋思路:

統計省份數據函數:傳入從log文件讀取的一行,切割取得數組,獲得需要修改數據的省份人數數量以及操作類型,然後判別省份個數(1個|2個),進而判別哈希表中是否存在該省份,如果存在,說明該省前面已經統計過部分數據,所以從哈希表中取出;如果不存在,則創建一個Province類;接着將省份、人數數量、操作類型傳入執行操作的靜態方法executeOperate(),執行相應的操作;操作完成後,之前新建的Province類要put進哈希表。

統計全國數據:統計完所有日誌文檔後,新建一個全國的Province實例wholeNation,遍歷哈希表,累計各項屬性的值,賦給wholeNation的相應屬性,再將wholeNation存入哈希表

寫入文件

/**
* description:寫入文件
* @param hashtable 保存着所有參與統計的省份
* @param fileOutputStream 輸出文件流
* @param paramenterOfType數組 -type的參數值
* @param paramenterOfProvice數組 -province的參數值
* @param commandLineStrings數組 命令行數組 argv
*/
public static void writeFile(Hashtable<String, Province> hashtable, FileOutputStream fileOutputStream, 
                             String[] paramentersOfType, String[] paramentersOfProvince,String[] commandLineStrings) {
    String endLineString = "// 該文檔並非真實數據,僅供測試使用";
    String commandLineString = "// 命令:";
    for(int i=0; i<commandLineStrings.length; i++) {
        commandLineString = commandLineString + commandLineStrings[i] + " ";
    }
    InfectStatistic infectStatistic = new InfectStatistic();
    Province wholeNation = hashtable.get("全國");
    try {

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"UTF8");

        if(paramentersOfProvince[0].equals("null")) {   //沒有指定省份
            Set set = hashtable.keySet();
            Iterator iterator = set.iterator();
            List<Map.Entry<String,Province>> list = OpHashTableMethods.sortByHeadAlphabet(hashtable);       //排序
            for (Map.Entry entry : list){
                Province province = (Province) entry.getValue();

                if(paramentersOfType[0].equals("null")) {   //沒有指定輸出類型
                    outputStreamWriter.write(province.getAllResult() + "\r\n");
                    outputStreamWriter.flush();
                }else {
                    outputStreamWriter.write(province.getResultByRequest(paramentersOfType) + "\r\n");
                    outputStreamWriter.flush();
                }
            }
            outputStreamWriter.write(endLineString + "\r\n" + commandLineString);
            outputStreamWriter.flush();
        }else { //指定省份
            Hashtable<String, Province> requestProvinceHashtable = new Hashtable<String, InfectStatistic.Province>();
            //                    for(int i=0; i<paramentersOfProvince.length; i++) {   // 別用.length,指定的省的個數不一定等於數組的大小
            for(int i=0; paramentersOfProvince[i] != null; i++) {
                if(!hashtable.containsKey(paramentersOfProvince[i])) {  //哈希表中不存在
                    Province province = infectStatistic.new Province(paramentersOfProvince[i], 0, 0, 0, 0);
                    requestProvinceHashtable.put(paramentersOfProvince[i], province);
                }else { //哈希表中存在
                    Province province = hashtable.get(paramentersOfProvince[i]);
                    requestProvinceHashtable.put(paramentersOfProvince[i], province);
                }
            }

            List<Map.Entry<String,Province>> list = OpHashTableMethods.sortByHeadAlphabet(requestProvinceHashtable);       //排序

            for (Map.Entry entry : list){
                Province province = (Province) entry.getValue();

                if(paramentersOfType[0].equals("null")) {   //沒有指定輸出類型
                    outputStreamWriter.write(province.getAllResult() + "\r\n");
                    outputStreamWriter.flush();
                }else {
                    outputStreamWriter.write(province.getResultByRequest(paramentersOfType) + "\r\n");
                    outputStreamWriter.flush();
                }
            }
            outputStreamWriter.write(endLineString + "\r\n" + commandLineString);
            outputStreamWriter.flush();
        }

    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
}

解釋思路:

主要是判斷用戶是否傳入了-type和-province,有四種組合,不過該方法裏主要判別province,有無type只要通過調用Province不同的方法來輸出不同的結果即可,所以主要兩大類:

  • 沒有指定省份

先對哈希表排序,然後遍歷哈希表,再判別有無-type,調用Province的方法打印該省的相應數據

  • 指定了省份

新建一個保存指定省份信息的哈希表requestProvinceHashtable遍歷指定的所有省份,判斷傳入的哈希表hashtable(即保存着在log中出現的所有省份的數據)中是否存在當前的省(指定輸出的省份可能沒在log文件中出現),如果不存在,新建該省份的Province實例,並加入requestProvinceHashtable,如果存在,從hashtable中取出該省,並加入requestProvinceHashtable,因此requestProvinceHashtable中保存了想要輸出的省份的數據,然後排序requestProvinceHashtable,再遍歷輸出

Province的兩個獲得結果的方法:

/**
* description:打印全部統計的數據結果
* @return resString 返回值爲字符串
*/
public String getAllResult() {
    String resString = provinceName + " " + "感染患者" + ip + "人" + " " + "疑似患者" + sp + "人" + " " + "治癒" + cure
        + "人" + " " + "死亡" + dead + "人";
    return resString;
}

/**
* description:按指定參數值要求給出結果
* @param paramenterOf 一個保存着-type的參數值的數組
* @return resString 返回值爲字符串
*/
public String getResultByRequest(String[] paramentersOfType) {
    String resString = provinceName + " ";
    for(int i=0; paramentersOfType[i] != null; i++) {
        switch (paramentersOfType[i]) {
            case "ip":
                resString += "感染患者" + " " + ip + "人" + " ";
                break;
            case "sp":
                resString += "疑似患者" + " " + sp + "人" + " ";
                break;
            case "cure":
                resString += "治癒" + " " + cure + "人" + " ";
                break;
            case "dead":
                resString += "死亡" + " " + dead + "人" + " ";
                break;
            default:
                break;
        }
    }

    return resString;
}

命令行的處理

HashMap<Integer, String> paramenterHashMap = new HashMap<Integer, String>(5);
paramenterHashMap.put(1, "-log");
paramenterHashMap.put(2, "-out");
paramenterHashMap.put(3, "-date");
paramenterHashMap.put(4, "-type");
paramenterHashMap.put(5, "-province");

String[] paramenterStrings = new String[args.length - 1];   //存儲傳入的參數名、參數值
for(int i=1; i<args.length; i++) {
    paramenterStrings[i-1] = args[i];
}

int[] indexOfParamenterStrings = {-1, -1, -1, -1, -1, -1};
//找到參數名,並記錄位置
for(int i=0; i<paramenterStrings.length; i++) {
    int key = OpHashTableMethods.getKey(paramenterHashMap, paramenterStrings[i]);
    if( key != -1) {   //是參數名
        indexOfParamenterStrings[key] = i;   //key對應的參數名在patamenterStrings的i下標位置,值爲-1則代表無此參數名
    }
}


/**
* 初始化輸入路徑、輸出路徑、截至日期、type參數值、province參數值
*/
String directoryString = "./log";   // log 日誌文件目錄,項目必會附帶,如果沒有,從項目裏的log取
String outputFileNameString = "./result/testOutput.txt";    //輸出路徑/文件名
String toDateString = GetFileMethods.getToday(); //統計到哪一天
String[] paramentersOfType = new String[10];;  //type的參數值
String[] paramentersOfProvince = new String[25];  //province的參數值
paramentersOfType[0] = "null";
paramentersOfProvince[0] = "null";

//接着處理每個參數名對應的參數值
for(int i=1; i<=5; i++) {
    if(indexOfParamenterStrings[i] != -1) { //傳入了該參數名
        if(i == 1) {    // -log
            directoryString = paramenterStrings[indexOfParamenterStrings[i] + 1];    //配置log路徑
        }else if(i == 2) {  //-out
            outputFileNameString = paramenterStrings[indexOfParamenterStrings[i] + 1];      //配置輸出文件路徑
        }else if(i == 3) {  //-date
            toDateString = paramenterStrings[indexOfParamenterStrings[i] + 1];  //統計到哪一天
        }else if(i == 4) {  //-type 可能會有多個參數
            String[] paramenterValues = new String[20]; //記錄所有參數值
            int cnt = 0;
            //取得參數值,直到找到下一個參數名時停止,   當前參數名 參數值1 參數值2 ... 下一個參數名
            for(int j=indexOfParamenterStrings[i]+1; 
                j<paramenterStrings.length && OpHashTableMethods.getKey(paramenterHashMap, paramenterStrings[j])==-1; j++) { 
                paramenterValues[cnt++] = paramenterStrings[j];
                paramentersOfType = paramenterValues;
            }
        }else if(i == 5) {  //-province
            String[] paramenterValues = new String[20];
            int cnt = 0;
            //取得參數值,直到找到下一個參數名時停止,   當前參數名 參數值1 參數值2 ... 下一個參數名
            for(int j=indexOfParamenterStrings[i]+1; 
                j<paramenterStrings.length && OpHashTableMethods.getKey(paramenterHashMap, paramenterStrings[j])==-1; j++) { 
                paramenterValues[cnt++] = paramenterStrings[j];
                paramentersOfProvince = paramenterValues;
            }
        }
    }
}

解釋說明:

用五個參數名初始化一個hashMap,用傳入的參數名、參數值初始化一個字符串數組paramenterStrings,用-1初始化一個大小爲6的int數組indexOfParamenterStrings,遍歷paramenterStrings,如果在hashMap中存在該值(該值爲參數名),則將該值在hashMap中對應的鍵作爲indexOfParamenterStrings的下標,將該值對應paramenterStrings的下標作爲indexOfParamenterStrings的值

例:indexOfParamenterStrings[4] = 6 代表的是hashMap中鍵爲4的參數名-type在paramenterStrings[6]中
indexOfParamenterStrings[4] = -1 則代表沒有傳入該參數

然後從下標1開始遍歷indexOfParamenterStrings(初始化hashMap時從1開始的),判斷是否傳入了該參數名,如果存在,從paramenterStrings中爲當前參數名的下一個位置開始取得參數值,直到paramenterStrings的盡頭或者遇到下一個參數名,然後用取得的參數值初始化相應的變量

單元測試截圖和描述

獲取字符串前的數字

測試用例

單元測試1

測試結果:

單元測試1-結果

獲得需要修改數據的省份

測試數據:

public String[] testStrings = {
    "福建 新增 感染患者 2人" ,
    "福建 新增 疑似患者 5人" ,
    "湖北 新增 感染患者 15人" , 
    "湖北 新增 疑似患者 20人" , 
    "湖北 感染患者 流入 福建 2人" , 
    "湖北 疑似患者 流入 福建 3人" , 
    "湖北 死亡 1人" ,
    "湖北 治癒 2人" , 
    "福建 疑似患者 確診感染 1人" ,
    "湖北 排除 疑似患者 2人" 
};

測試用例:

單元測試2

測試結果:

單元測試2-結果

判斷操作類型

測試用例:

單元測試10

測試結果:

單元測試10-結果

獲得最大日期

測試用例:

單元測試two

測試結果:

單元測試two-結果

獲得指定日期前的所有文件

測試用例:

單元測試3

測試結果:

單元測試3-結果1

單元測試3-結果2

按城市首字母排序,“全國”置頂

測試用例:

單元測試4

測試結果:

單元測試4-結果

統計省份數據

測試數據:

public String[] testStrings = {
   "福建 新增 感染患者 2人" ,
   "福建 新增 疑似患者 5人" ,
   "湖北 新增 感染患者 15人" , 
   "湖北 新增 疑似患者 20人" , 
   "湖北 感染患者 流入 福建 2人" , 
   "湖北 疑似患者 流入 福建 3人" , 
   "湖北 死亡 1人" ,
   "湖北 治癒 2人" , 
   "福建 疑似患者 確診感染 1人" ,
   "湖北 排除 疑似患者 2人" 
};

測試用例:

單元測試5

測試結果:

單元測試5-結果

統計全國的數據

測試用例:

單元測試6

測試結果:

單元測試6-結果

寫入文件

測試用例:

單元測試7

測試結果:

單元測試7-結果1

單元測試7-結果2

HashMap根據value獲取key

測試用例:

單元測試8

測試結果:

單元測試8-結果

單元測試覆蓋率優化和性能測試

覆蓋率測試

application覆蓋測試

項目覆蓋率

JUnit Test覆蓋測試

單元測試覆蓋率

性能測試

總覽

總覽

內存情況

內存情況

CPU

CPU

Live memory-classes

Live memory-classes

優化過程--性能優化&提升覆蓋率

性能優化

1.提取尋循環中可以重用的對象到循環外。在循環中new對象,不僅要花時間來創建,還要花時間對這些對象進行垃圾回收和處理

for(int i=0; i<nameStrings.length; i++) {
    Date tmpDate = dFormat.parse(nameStrings[i]);
    //...
}
改成 ↓
Date tmpDate = new Date(); 
for(int i=0; i<nameStrings.length; i++) {
    tmpDate = dFormat.parse(nameStrings[i]);
    //...
}

2.減少變量的重複計算,避免在循環條件中使用複雜的表達式

for(int i=0; i<nameStrings.length; i++) {...}
改成 ↓
for(int i=0, len=nameStrings.length; i<len; i++) {...}

3.將try/catch語句放到循環最外層

for(...){
    try{
    	/...   
    }catch{
        
    }
}
改成 ↓
try{
    for(...){}
}catch{
    
}

4.用散列值取出相應的Entry,來遍歷哈希表

List<Map.Entry<String,Province>> list = OpHashTableMethods.sortByHeadAlphabet(hashtable);       //排序
for (Map.Entry entry : list){
    province = (Province) entry.getValue();
	//...
}

5.字符串相加時,如果只有一個字符,用' ',不用“ ”

更改完代碼後性能檢測:

優化1(1)

優化1(2)

提升代碼覆蓋率

1.刪掉沒用的代碼,剛開始寫了,但是後來沒用到的函數等

示例:

覆蓋率優化-刪掉沒用代碼

2.改變判斷結構

示例:

覆蓋率優化1

修改後:

覆蓋率優化2

3.消除重複代碼

示例:

覆蓋率優化-消除重複代碼

修改後:

覆蓋率優化-消除重複代碼2

調整完覆蓋率測試

調整完覆蓋率測試

優化結果

性能優化

對比1

對比2

覆蓋率提升

對比3

代碼規範

https://github.com/904566722/InfectStatistic-main/blob/master/221701419/codestyle.md

心路歷程&收穫

這次的作業相較於第一次,量還是比較多的,看完第一遍之後的感受就是有許多不知道的東西,PSP、單元測試等等,觸及到了我的知識盲區...然後就決定先不管,先看看《編程之法》前三章,裏面提到了許多問題都是自己目前存在的,粗略列幾點來提醒自己:

  • 技止此耳? 看書的時候多思考此項技術及延伸,及時實踐發現同書上的不同,技術更新總是很快
  • 唯手熟爾。 不斷練習,把低層次常遇到的問題變成大腦的“自動操作”,才能做更高層次的隨機應變
  • 多測試結果。多對寫完的程序進行測試,多找Bug,寫更好的軟件、程序。寫完程序我總是很懶得去測試...
  • ...

寫到這裏了,這次任務就快要結束了,通過這次的學習還是收穫到不少,包括舊知識的複習、新知識的學習,這次的任務涉及到了很多的知識跟技術,Java、GitHub、PSP、單元測試等等,有一部分都是之前瞭解過、但不怎麼使用的,通過這次的學習,回顧了Java代碼的編寫,進一步瞭解了GitHub、markdown的一些使用技巧,學習到了PSP、單元測試、覆蓋率等等新的知識,以及很重要的對自我的反省,還是很充實的,收穫很多。

Android學習相關的5個倉庫

1.AndroidAllGuide

鏈接:https://github.com/904566722/AndroidAllGuide

簡介: 這是一份關於 Java、Kotlin、Dart、Android 、Flutter 的學習指南 , 本指南以 Java & Kotlin & Dart 的基礎語法知識作爲開始,涵蓋了大部分的語言知識點,幫助初學者入門

2.Android

鏈接:https://github.com/itheima1/Android

簡介: 收集Android方方面面的經典知識, 最新技術. 涵蓋Android方方面面的技術, 目前保持更新. 時刻與Android開發流行前沿同步.

3.BGAPhotoPicker-Android

鏈接:https://github.com/bingoogolapple/BGAPhotoPicker-Android

簡介: Android 圖片選擇、預覽、九宮格圖片控件、拖拽排序九宮格圖片控件

4.DDComponentForAndroid

鏈接:https://github.com/luojilab/DDComponentForAndroid

簡介: 一套完整有效的android組件化方案,支持組件的組件完全隔離、單獨調試、集成調試、組件交互、UI跳轉、動態加載卸載等功能

5.Coder

鏈接:https://github.com/CoderGuoy/Coder

簡介: 項目使用MVVM模式進行開發, Tablayout | 橫向佈局標籤,TextInputLayout | 文字輸入佈局 ,FloatingActionButton | 懸浮按鈕 等

原文出處:https://www.cnblogs.com/hhhqqq/p/12306200.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章