寒假作业2/2
这个作业属于哪个课程 | 2021春软件工程实践|W班 (福州大学) |
---|---|
这个作业要求在哪里 | 软工实践寒假作业(2/2) |
这个作业的目标 | 学会思考和有价值的提问 初步掌握GitHub和GitHub desktop的使用 完成10个commit |
作业正文 | 正文 |
其他参考文献 | 《码出高效_阿里巴巴Java开发手册》 |
阅读《构建之法》并提问
一、快速看完整部教材,列出你仍然不懂的5到10个问题
1.《构造之法》第四章
每人在各自独立设计、实现软件的过程中不免要犯这样那样的错误。在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。
看过第四章的内容,结对编程他们通过交流会不会浪费本应该一次解决的问题,而且只使用一个键盘,他们每个人的效率往往会低于两个人分头行动,设置一个对于该项目两人都适应的文档,分开工作会不会更加具有效率?
2.《构造之法》第七章
MSF提倡自下而上的计划,每个人有充分的权力估计并决定自己的任务需要多长时间。
现实中这种情况太过理想,很难实现。通常都是自上而下的进行,那在被安排的时间过于紧凑时,如何更好地安排任务时间?(排除主观因素的情况)
3.《构造之法》第十一章
在软件开发中,如何应用建模方法?
书上只提出来软件开发时的模型,但是并没有提出如何在实际情况下建立一个符合现实的建筑模型。也没有具体提出在建模之后,如何进一步地完成任务,只是抽象地描述了建模时每个部分的作用,让软件开发时的我们无法开始下一步活动。能否对这个模型提出更具体的步骤?或是让这个模型变得更具体?
4.《构造之法》第十六章
其实,大部分成功的创新者都不是先行者,例如搜索引擎,Google是很晚才进入这个领域的。
我认为创新者绝对是能在他创新领域里最占优势的一个,他在绝大多数可能下会成为成功者。而那些例如谷歌的后来者,他们很有可能一部分的人是来源于创新者的,并且他们的平台资源更优秀才导致他们在这个领域里更加成功。
5.《构造之法》第十六章
以发明即时贴(Post-It)闻名世界的3M公司的杰弗里·尼科尔森(Geoffrey Nicholson)对两者做了明确的区分,他认为“科研是将金钱转换为知识的过程”,而“创新则是将知识转换为金钱的过程”。
网上对科研的定义为:科学研究(Scientific research),一般是指利用科研手段和装备,为了认识客观事物的内在本质和运动规律而进行的调查研究、实验、试制等一系列的活动,为创造发明新产品和新技术提供理论依据。科学研究的基本任务就是探索、认识未知。 它并没有指明与金钱的关系。那科研一定是需要金钱来支撑的嘛?是否有能够不需要金钱完成的科研成果?而创新是否一定是知识转换为金钱?是否有可能是知识转化成另一种知识?
二、附加题
Bug的由来?
1945年9月,编译器发明者格蕾斯•哈珀正领着她的小组构造马克二型计算机。突然,马克二型死机了。哈珀在某出错继电器上发现一只被电死的飞蛾;她将蛾子贴到记事本中并注明,第一个发现虫子实例。从此,人们将计算机错误戏称为Bug,将发现Bug并纠正的过程叫Debug。
——来自知乎https://zhuanlan.zhihu.com/p/28062384
WordCount编程
项目GitHub地址:
本次作业的PSG表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 800 min | 960 min |
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | 200min | 250min |
• Design Spec | • 生成设计文档 | 30min | 30 min |
• Design Review | • 设计复审 | 50min | 60min |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20min | 20min |
• Design | • 具体设计 | 50min | 50min |
• Coding | • 具体编码 | 300min | 400min |
• Code Review | • 代码复审 | 50min | 50min |
• Test | • 测试(自我测试,修改代码,提交修改) | 20 min | 20min |
Reporting | 报告 | ||
• Test Repor | • 测试报告 | 30min | 30min |
• Size Measurement | • 计算工作量 | 20min | 20min |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 20min | 20min |
合计 | 800min | 960min |
解题思路描述
编写一个可以读取文件信息的java程序,它具有检查文件中字符个数,单词总数,统计有效行数,出现频率最高的10个单词的出现次数,并将它输出到input.txt文件中。
从题目来看我们需要做到的功能有以下六个:
1.读取文件信息
2.检查文件中字符数
3.检查单词总数
4.统计有效行数
5.统计出现频率最高的10个单词的出现次数
6.输出统计内容到指定的输出文件中
完成这6个功能再将文件的输入参数改为使用cmd传入就能实现要求,找寻资料大致的方向一是如何读取文件,二者是如何储存统计的数据。
代码规范制定链接
设计与实现过程
我是将所有个功能函数放在lib类中,主函数放在wordcount类中。由于每个函数都需要读取文件,以下代码不予赘余。
根据思路一共需要实现6个功能
1.检查文件中字符数
使用BufferedReader类对象读取文件,然后创建一个char来判断获取的字符是否是ASCLL码,如符合规则,记录字符的变量countchar便加一。
while((ch=(char)br.read())!=(char)-1)
{
if(ch<=127)//保证读取的字符为ASCLL码
{
countChar++;
}
}
2.检查单词总数
使用BufferedReader类对象读取文件,使用strs字符数组储存传入的数据,同时将传入的字符串用正则表达式分隔。对已经划分好的字符串strs使用正则表达式判断分隔开单词是否满足仅有单词和数字构成且以四个单词为开头。如果存在记录变量countword便加一。
String[] strs=words.split("[^a-zA-Z0-9]");
String regexs = "^[a-zA-Z]{4,}.*";
for(int i=0;i<strs.length;i++)
{
if(strs[i].matches(regexs))
{
countWord++;
}
}
3.统计有效行数
使用BufferedReader类对象读取文件,使用reanline方法读取行数,因为要排除空行对有效行数的影响,需要将换行符等筛掉。
for (int i=0;i<c.length;i++)
{
if (c[i]!='\n' && c[i]!='\r' && c[i]!='\t')
{
countLine++;
break;
}
}
4.统计出现频率最高的10个单词的出现次数
使用BufferedReader类对象读取文件,使用map来排除已经记录过的单词并让频率加一,使用map来保存出现过的单词,并变成全小写形式。
for (int i = 0; i < strs.length; i++) {
if (strs[i].matches(regexs)) {
if (!map.containsKey(strs[i].toLowerCase())) {
map.put(strs[i].toLowerCase(), 1);
} else {
int num = map.get(strs[i].toLowerCase());
map.put(strs[i].toLowerCase(), num + 1);
}
}
}
将所有map存储的键值对存储在list链表中,重载compare函数,首先对频次按照从高到低排序,若出现了频数一致的情况,则需要按照字典序从小到大排序。
list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
list.sort(new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
if(o1.getValue().equals(o2.getValue())) {
//频率相同按字典序排序
return o1.getKey().compareTo(o2.getKey());
}
else
//按值排序
return o2.getValue().compareTo(o1.getValue());
}
});
}
5.输出统计内容到指定的输出文件中
使用stringbuilder来存储读取的字符,使用str的append拼写方法将要求输出的内容组合在一起,使用OutputStreamWriter的wirte方法将str的数据写入输出文件中
StringBuilder str = new StringBuilder();
str.append("characters: "+countChar+"\n" + "words: "+countWord+"\n" +"lines: "+countLine+"\n"s);
for(int i = 0;i<(list.size()<10 ? list.size():10);i++){
str.append(list.get(i).getKey()+": "+list.get(i).getValue()+"\n");
}
性能改进
将InputStream改成BufferedReader 提高了读取时的效率
时间太短 提升的不够明显
单元测试
数据:
预想结果
单元测试代码
1.字符数
void getCountChar() throws IOException {
String str = "D://input.txt";
Lib lib = new Lib(str,null);
int c=lib.getCountChar();
Assert.assertEquals(21,c);
}
2.列数
void getLineCount() throws IOException {
String str = "D://input.txt";
Lib lib = new Lib(str,null);
int c=lib.getLineCount();
Assert.assertEquals(3,c);
}
3.单词数
void getWordNum() throws IOException {
String str = "D://input.txt";
Lib lib = new Lib(str,null);
int c=lib.getWordNum();
Assert.assertEquals(2,c);
}
4.出现频率的10个单词及其单词频率
因输出格式的原因无法使用单元测试出现结果 但是经过测试是正确的 测试结果如下:
代码覆盖率
如何优化覆盖率
将读取单独设立一个函数 减少读取出错的可能性
异常处理说明
1.所有的函数都加入了FileNotFoundException和IOException异常处理。
2. 对cmd命令输入错误进行了处理
if (args.length < 2) {
System.err.println("please input more than 2 chars!");
return;
}
心路历程与收获
对原本学得不牢固的java读取文件等知识进行了巩固。学会了使用github上传自己的代码,初步编写了自己的代码规范和使用文档,学习到了以后学习需要运用到的技能。这是本课程第一次进行编程,也是学习到了很多新的技术和技能,在查询资料的同时,将不懂的内容和同学讨论,也意识到自己的薄弱环节,学习到了很多。希望在以后的项目里能够继续学习到新技能,把自己的java技术继续磨练,争取做到最好。