第4周小组作业:WordCount优化
Github項目地址:https://github.com/chaseMengdi/wcPro
stage1:代碼編寫+單元測試
PSP表格
| PSP2.1 | PSP階段 | 預(yù)估耗時(分鐘) | 實際耗時(分鐘) |
| Planning | 計劃 | 25 | 30 |
| Estimate | 估計任務(wù)需要多少時間 | 25 | 30 |
| Development | 開發(fā) | 300 | 302 |
| Analysis | 需求分析 | 20 | 20 |
| Design Spec | 生成設(shè)計文檔 | 20 | 15 |
| Design Review | 設(shè)計復(fù)審 | 20 | 15 |
| Coding Standard | 代碼規(guī)范 | 20 | 15 |
| Design | 具體設(shè)計 | 20 | 25 |
| Coding | 具體編碼 | 90 | 80 |
| Code Review | 代碼復(fù)審 | 20 | 30 |
| Test | 測試 | 60 | 80 |
| Reporting | 報告 | 80 | 95 |
| Test Report | 測試報告 | 30 | 50 |
| Size Measurement | 計算工作量 | 30 | 25 |
| Postmortem | 總結(jié) | 20 | 20 |
| ? | 合計 | 405 | 430 |
描述代碼設(shè)計思路
接口設(shè)計
public?static?HashMap<String,?Integer>?count(String?thefile)
劃分統(tǒng)計單詞數(shù)
接口實現(xiàn)
count()函數(shù)傳入的是一個文件名,即txt文件名,通過逐行讀取文件,先將字符串轉(zhuǎn)換為小寫,通過split()函數(shù)對字符串進行劃分。個人技術(shù)有限,發(fā)現(xiàn)當(dāng)字符串的最前面的字符是非字母的時候,split()劃分會出現(xiàn)不知名的空,故在使用split()進行劃分前需要先去掉字符串最前面的非字母字符,同時還有注意“-”出現(xiàn)的情況,如—word-word---,---,需要去開頭的“-”和結(jié)尾的“-”,而保留詞與詞間的“-”。然后進行單詞統(tǒng)計,將結(jié)果存放在HashMap<String, Integer>中。
// 劃分統(tǒng)計單詞數(shù)public static HashMap<String, Integer> count(String thefile) {File file = new File(thefile);HashMap<String, Integer> map = new HashMap<>();if (file.exists()) {try {FileInputStream fis = new FileInputStream(file);InputStreamReader isr = new InputStreamReader(fis, "UTF-8");BufferedReader br = new BufferedReader(isr);String line = new String("");StringBuffer sb = new StringBuffer();while ((line = br.readLine()) != null) {// 轉(zhuǎn)為小寫 line = line.toLowerCase();int k = 0;// 去除行首的非字母單詞char first = line.charAt(k);while (!((first >= 'a' && first <= 'z') || first == '-')) {k++;first = line.charAt(k);}line = line.substring(k);// 去除多個空格\\s+ String[] split = line.split("\\s++|0|1|2|3|4|5|6|7|8|9|\\_|\\'|\\.|\\,|\\;|\\(|\\)|\\~|\\!|"+ "\\@|\\#|\\$|\\%|\\&|\\*|\\?|\""+ "|\\[|\\]|\\<|\\>|\\=|\\+|\\*|\\/|\\{|\\}|\\:|\\||\\^|\\`");for (int i = 0; i < split.length; i++) {// 獲取到每一個單詞 Integer integer = map.get(split[i]);// 考慮末尾為-的單詞或開頭為---if ((split[i].endsWith("-") || split[i].startsWith("-"))&& !(split[i].equals("-"))) {// 去除多個空格\\s+ String[] sp = split[i].split("\\s++|\\-");// 全部為----if (sp.length == 0) {split[i] = "-";integer = map.get(split[i]);}// 處理--danelse if (split[i].startsWith("-")) {int j = 0;char si = split[i].charAt(0);while (split[i].charAt(j) == si)j++;split[i] = split[i].substring(j);integer = map.get(split[i]);}// 去除多個空格\\s+ sp = split[i].split("\\s+|\\-");// 全部為----if (sp.length == 0) {split[i] = "-";integer = map.get(split[i]);}// 處理dn-dan---else {String tmp = sp[0];for (int j = 1; j < sp.length; j++) {tmp = tmp + "-" + sp[j];}split[i] = tmp;integer = map.get(split[i]);}}if (!split[i].equals("") && !split[i].equals("-")) {// 如果這個單詞在map中沒有,賦值1if (null == integer) {map.put(split[i], 1);} else {// 如果有,在原來的個數(shù)上加上一 map.put(split[i], ++integer);}}}}sb.append(line);br.close();isr.close();fis.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}} else {System.out.print("文件不存在\n");}return map;}?
測試設(shè)計過程
count()函數(shù)的測試設(shè)計應(yīng)以黑盒設(shè)計為主,首先創(chuàng)建并初始化一個HashMap<String, Integer>和txt文件,隨后將txt文件名傳入count(),將實際輸出與期望輸出利用斷言進行對比。
20個測試用例設(shè)計如下:
?
| Test Case ID 測試用例編號 | Test Item 測試項(即功能模塊或函數(shù)) | Test Case Title 測試用例標(biāo)題 | Test Criticality 重要級別 ? | Pre-condition 預(yù)置條件 | Input 輸入 | Output 預(yù)期結(jié)果 Result | Status | Remark 備注 |
| count_01 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,小寫 | ????? L | txt文件存在 | 01.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_02 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,小寫 | L | txt文件存在 | 02.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_03 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫混合 | L | txt文件存在 | 03.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_04 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫混合 | L | txt文件存在 | 04.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_05 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+連字符混合 | L | txt文件存在 | 05.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_06 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符混合 | L | txt文件存在 | 06.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_07 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+連字符(任意位置)混合 | L | txt文件存在 | 07.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_08 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符(任意位置)混合 | L | txt文件存在 | 08.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_09 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+單引號混合 | L | txt文件存在 | 09.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_10 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符(任意位置)+單引號混合 | L | txt文件存在 | 10.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_11 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+連字符+雙引號混合 | L | txt文件存在 | 11.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_12 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符(任意位置)+單引號+雙引號混合 | L | txt文件存在 | 12.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_13 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+連字符(任意位置)+雙引號+數(shù)字混合 | M | txt文件存在 | 13.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_14 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符(任意位置)+單引號+雙引號+數(shù)字混合 | M | txt文件存在 | 14.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_15 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+連字符(任意位置)+雙引號+數(shù)字(任意位置)混合 | M | txt文件存在 | 15.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_16 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符(任意位置)+單引號+雙引號+數(shù)字(任意位置)混合 | M | txt文件存在 | 16.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_17 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+連字符(任意位置)+雙引號+數(shù)字(任意位置)+常見符號混合 | M | txt文件存在 | 17.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_18 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符(任意位置)+單引號+雙引號+數(shù)字(任意位置)+常見符號混合 | H | txt文件存在 | 18.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_19 | 劃分統(tǒng)計單詞數(shù) | 一個單詞,大小寫+連字符(任意位置)+雙引號+數(shù)字(任意位置)+常見符號混合 | H | txt文件存在 | 19.txt | 單詞與詞頻 | OK | 黑盒測試 |
| count_20 | 劃分統(tǒng)計單詞數(shù) | 多個單詞,大小寫+連字符(任意位置)+單引號+雙引號+數(shù)字(任意位置)+常見符號+詞頻相同混合 | H | txt文件存在 | 20.txt | 單詞與詞頻 | OK | 黑盒測試 |
?
測試運行和評價
count(String thefile)的單元測試的數(shù)據(jù)量和復(fù)雜度逐漸增加,符合測試用例設(shè)計規(guī)范,所有單元測試均通過。
count(String thefile)函數(shù)質(zhì)量水平較高,可以正常的劃分字符串和統(tǒng)計單詞。
小組貢獻
我負(fù)責(zé)的是劃分統(tǒng)計單詞數(shù),這是本程序流程的第二步,如果出現(xiàn)錯誤,將會引起連鎖反應(yīng)致使本程序不能正確運行,所以這部分的正確性是很重要。
剛開始用split()對字符串進行分割,但后來發(fā)現(xiàn)如果字符串的開始部分是分割字符將會導(dǎo)致分割到的第一個字符串為空(不知道為什么),故本人加入一個去除以非字母開始的字符直到出現(xiàn)第一個字母。由于出現(xiàn)“-”的單詞有幾種情況,還需要對它們進行判斷處理。
我個人的代碼行數(shù)占了0.51,主要是要求有點多,需要考慮的情況較多,個人覺得應(yīng)該還是完成的挺不錯的.
stage2:靜態(tài)測試
開發(fā)規(guī)范理解
《阿里巴巴Java開發(fā)手冊》中指出:
2. 【強制】代碼中的命名嚴(yán)禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。 說明:正確的英文拼寫和語法可以讓閱讀者易于理解,避免歧義。注意,即使純拼音命名方式也要避免采用。
正例:alibaba / taobao / youku / hangzhou 等國際通用的名稱,可視同英文。
反例:DaZhePromotion [打折] / getPingfenByName() [評分] / int 某變量 = 3
理解:
我覺得這點規(guī)定非常好,因為正確的英文拼寫和語法可以讓閱讀者易于理解,避免歧義。而拼音英文混合和中文命名代碼的方式則不利于讀者閱讀代碼,也不利于性能優(yōu)化和同行評審。我負(fù)責(zé)的單詞統(tǒng)計模塊代碼命名均為國機通用的英文,符合《阿里巴巴Java開發(fā)手冊》第二條的強制規(guī)定。
組員代碼評價
選擇劉博謙(17070)的代碼進行分析
// 詞頻排序public static ArrayList<String> sort(HashMap<String, Integer> map) {// 以Key進行排序TreeMap treemap = new TreeMap(map);// 以value進行排序ArrayList<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(treemap.entrySet());Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {public int compare(Map.Entry<String, Integer> o1,Map.Entry<String, Integer> o2) {// 降序return o2.getValue() - o1.getValue();// 升序 o1.getValue() - o2.getValue()) }});ArrayList<String> str = new ArrayList<String>();int i = 0;for (Map.Entry<String, Integer> string : list) {// 排除-與空格if (!(string.getKey().equals("")) && !(string.getKey().equals("-"))) {str.add(string.getKey());str.add(string.getValue().toString());// 輸出前1000個單詞if (i > 1000)break;i++;}}return str;}?
劉博謙的代碼遵守了《阿里巴巴Java開發(fā)手冊》第二條的強制規(guī)定,代碼命名規(guī)范,無需改進。
靜態(tài)代碼檢查
選擇工具:FindBugs 3.0.1
下載鏈接:http://findbugs.sourceforge.net/
檢查結(jié)果如下:
String line = new String("");
缺陷信息:
Method invokes inefficient new String(String) constructor
Using the java.lang.String(String) constructor wastes memory because the object so constructed will be functionally indistinguishable from the String passed as a parameter.? Just use the argument String directly.
Bug kind and pattern: Dm - DM_STRING_CTOR
分析:new String("")構(gòu)造函數(shù)效率低,直接line=""即可。
個人代碼改進
個人代碼符合《阿里巴巴Java開發(fā)手冊》第二條的強制規(guī)定,改正FindBugs指出的缺陷后,代碼如下。
(完整代碼過于繁瑣,下面只貼出缺陷部分代碼修改后的結(jié)果)
?
FileInputStream fis = new FileInputStream(file);InputStreamReader isr = new InputStreamReader(fis, "UTF-8");BufferedReader br = new BufferedReader(isr);String line = "";StringBuffer sb = new StringBuffer();?
?
小組代碼分析
(此部分由本人和劉博謙(17070)完成)
1、FileWriter writer = new FileWriter("result.txt", true);
寫文件流可能關(guān)閉異常,應(yīng)該使用try/finally來確保寫文件流會被成功關(guān)閉。
原有代碼中使用了try/catch,但是并未使用finally語句,這就導(dǎo)致如果出現(xiàn)錯誤跳到catch,程序繼續(xù)執(zhí)行的話,寫文件流一直會被占用,從而可能引發(fā)程序崩潰。
建議添加finally塊來關(guān)閉寫文件流。
2、FileWriter writer = new FileWriter("result.txt", true);
此行語句需要依賴默認(rèn)編碼來正常工作,為防止隱藏bug,應(yīng)該指定一個編碼,考慮到程序需求,指定UTF-8編碼。
3、String line = new String("");
new String("")構(gòu)造函數(shù)效率低,直接line=""即可。
4、message += (str.get(i) + " " + str.get(i + 1) + "\r\n");
循環(huán)中使用+來連接字符串,時間開銷為二次方,建議修改使用StringBUffer.append(String)方法來提高效率。
參考資料
1、單詞詞頻統(tǒng)計降序排序(代碼貼)
2、阿里巴巴Java開發(fā)手冊
轉(zhuǎn)載于:https://www.cnblogs.com/jakejian/p/8735660.html
總結(jié)
以上是生活随笔為你收集整理的第4周小组作业:WordCount优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何设计一个好的数据结构?
- 下一篇: SQL SERVER深入学习学习资料参考