软工实践寒假作业(2/2)
这个作业属于哪个课程 | 2020春|S班 (福州大学) |
---|---|
这个作业要求在哪里 | 寒假作业(2/2) |
这个作业的目标 | 开发一个疫情统计程序 |
作业正文 | 软工实践寒假作业(2/2) |
其他参考文献 | Github |
Github仓库地址 |
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 20 |
Estimate | 估计这个任务需要多少时间 | 5 | 5 |
Development | 开发 | 300 | 180 |
Analysis | 需求分析 (包括学习新技术) | 120 | 240 |
Design Spec | 生成设计文档 | 30 | 50 |
Design Review | 设计复审 | 10 | 60 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
Design | 具体设计 | 30 | 30 |
Coding | 具体编码 | 30 | 30 |
Code Review | 代码复审 | 30 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 60 | 60 |
Reporting | 报告 | 30 | 60 |
Test Repor | 测试报告 | 30 | 10 |
Size Measurement | 计算工作量 | 10 | 5 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 20 |
合计 | 755 | 850 |
解题思路描述
阅读题目 理解题目
发现java的知识忘得差不多了 先去网上查了点cmd运行java的资料 理解题目中的“命令”“命令行参数”“参数”是什么意思
理解题目的需求 是对信息按规定要求的整理
仔细理解每个要求的具体内容 保证不出错
每个信息有他的子信息 首先想到构造结构体(java中是类的实例) 把单个省份的情况封装起来进行操作
读取用字符串数组“命令”“命令行参数”“参数” 并按各个参数产生分支 再处理各个分支的具体工作
发现文件中有几种固定的格式并用空格分开 想到用空格分割字符串 再按格式中关键字的前后文读出具体的信息
实现过程
代码说明
读取参数
public static void readParameter(String args[]) {
for(int i = 0;i<args.length;i++) {
if(args[i].equals("-log"))
path = args[i+1];
if(args[i].equals("-out"))
out = args[i+1];
if(args[i].equals("-date"))
date = args[i+1];
if(args[i].equals("-type")) {
i++;
while(i < args.length&&args[i].charAt(0) != '-') {
type.add(args[i]);
i++;
}
i--;
}
if(args[i].equals("-province")) {
i++;
while(i < args.length&&args[i].charAt(0) != '-') {
province.add(args[i]);
i++;
}
i--;
}
}
}
读取-path目录下的文件 在读取完-date参数对应的文件后退出 用信息中的关键字判断读入的方式
public static void readFile(File[] tempList) throws NumberFormatException, IOException {
if(!date.equals("")) {
if(tempList[tempList.length-1].getName().toString().substring(0,10).compareTo(date)<0) {
System.out.print("日期超出范围!");
System.exit(0);
}
}
for(int i=0;i<tempList.length;i++) {
if(tempList[i].isFile()) {
if(!date.equals("")) {
if(tempList[i].getName().toString().substring(0,10).compareTo(date)>0) {
break;
}
}
BufferedReader br = new BufferedReader(
new UnicodeReader(
new FileInputStream(tempList[i]),
"UTF-8"));
InputStreamReader read = new InputStreamReader(new FileInputStream(tempList[i]), "UTF-8");
BufferedReader reader = new BufferedReader(read);
String str;
while ((str = br.readLine())!= null) {
String[] arrays = str.split("\\s+");
for(int j = 0;j<arrays.length;j++) {
Info t = new Info();
switch(arrays[j]) {
case "新增":
t.province=arrays[j-1];
if(list.contains(t)) {
if(arrays[j+1].equals("感染患者")) {
list.get(list.indexOf(t)).infected+=Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
all.infected += Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
else {
list.get(list.indexOf(t)).suspected+=Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
all.suspected += Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
}
else {
if(arrays[j+1].equals("感染患者")) {
t.infected = Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
all.infected += Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
else {
t.suspected = Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
all.suspected += Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
list.add(t);
}
break;
case "流入":
Info from = new Info();
Info to = new Info();
from.province = arrays[j-2];
to.province = arrays[j+1];
if(list.contains(to)) {
if(arrays[j-1].equals("感染患者")) {
list.get(list.indexOf(from)).infected -= Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
list.get(list.indexOf(to)).infected += Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
else {
list.get(list.indexOf(from)).suspected -= Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
list.get(list.indexOf(to)).suspected += Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
}
else {
if(arrays[j-1].equals("感染患者")) {
list.get(list.indexOf(from)).infected -= Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
to.infected = Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
else {
list.get(list.indexOf(from)).suspected -= Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
to.suspected = Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
}
list.add(to);
}
break;
case "死亡":
t.province = arrays[j-1];
list.get(list.indexOf(t)).infected -= Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
list.get(list.indexOf(t)).dead += Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
all.infected -= Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
all.dead += Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
break;
case "治愈":
t.province = arrays[j-1];
list.get(list.indexOf(t)).infected -= Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
list.get(list.indexOf(t)).cured += Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
all.infected -= Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
all.cured += Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
break;
case "确诊感染":
t.province = arrays[j-2];
list.get(list.indexOf(t)).suspected -= Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
list.get(list.indexOf(t)).infected += Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
all.suspected -= Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
all.infected += Integer.parseInt(arrays[j+1].substring(0,arrays[j+1].length()-1));
break;
case "排除":
t.province = arrays[j-1];
list.get(list.indexOf(t)).suspected -= Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
all.suspected -= Integer.parseInt(arrays[j+2].substring(0,arrays[j+2].length()-1));
break;
default:
break;
}
}
}
reader.close();
br.close();
}
}
Collections.sort(list, new Comparator<Info>() {
@Override
public int compare(Info o1, Info o2) {
// TODO Auto-generated method stub
Comparator<Object> com = Collator.getInstance(java.util.Locale.CHINA);
return com.compare(o1.province, o2.province);
}
});
}
输出到命令行检查 写入-out路径的文件 根据-province和-type的有无判断输出和写入方式
public static void out() throws IOException {
FileWriter fw = new FileWriter(out);
BufferedWriter fout = new BufferedWriter(fw);
if(province.size()>0) {
if(province.contains("全国")) {
printTypeInfo(all, type,fout);
}
if(type.size()>0) {
for(int k = 0;k<province.size();k++) {
Info t = new Info();
t.province = province.get(k);
if(list.contains(t)) {
printTypeInfo(list.get(list.indexOf(t)), type, fout);
}
else {
printTypeInfo(t, type, fout);
}
}
}
else {
for(int k = 0;k<province.size();k++) {
Info t = new Info();
t.province = province.get(k);
if(list.contains(t)) {
printInfo(list.get(list.indexOf(t)), fout);
}
else {
printInfo(t, fout);
}
}
}
}
else {
if(type.size()>0) {
for(int k = 0;k<list.size();k++) {
printTypeInfo(list.get(k), type, fout);
}
}
else {
printInfo(all,fout);
for(int k = 0;k < list.size();k++) {
printInfo(list.get(k),fout);
}
}
}
fout.close();
}
无法确定读入的文件的编码方式 统一在读取时去除BOM防止意外的字符
class UnicodeReader extends Reader { //工具类用于读取文件去除BOM
PushbackInputStream internalIn;
InputStreamReader internalIn2 = null;
String defaultEnc;
private static final int BOM_SIZE = 4;
UnicodeReader(InputStream in, String defaultEnc) {
internalIn = new PushbackInputStream(in, BOM_SIZE);
this.defaultEnc = defaultEnc;
}
public String getDefaultEncoding() {
return defaultEnc;
}
public String getEncoding() {
if (internalIn2 == null) return null;
return internalIn2.getEncoding();
}
protected void init() throws IOException {
if (internalIn2!=null) return;
String encoding;
byte bom[] = new byte[BOM_SIZE];
int n,unread;
n = internalIn.read(bom, 0, bom.length);
if ( (bom[0] == (byte)0x00) && (bom[1] == (byte)0x00) &&
(bom[2] == (byte)0xFE) && (bom[3] == (byte)0xFF) ) {
encoding = "UTF-32BE";
unread = n-4;
} else if ( (bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) &&
(bom[2] == (byte)0x00) && (bom[3] == (byte)0x00) ) {
encoding = "UTF-32LE";
unread = n-4;
} else if ( (bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB) &&
(bom[2] == (byte)0xBF) ) {
encoding = "UTF-8";
unread = n-3;
} else if ((bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF)) {
encoding = "UTF-16BE";
unread = n-2;
} else if ((bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE)) {
encoding = "UTF-16LE";
unread = n-2;
} else {
// Unicode BOM mark not found, unread all bytes
encoding = defaultEnc;
unread = n;
}
//System.out.println("read=" + n + ", unread=" + unread);
if (unread>0)
internalIn.unread(bom,(n-unread),unread);
// Use given encoding
if (encoding == null) {
internalIn2 = new InputStreamReader(internalIn);
} else {
internalIn2 = new InputStreamReader(internalIn, encoding);
}
}
public void close() throws IOException {
init();
internalIn2.close();
}
public int read(char[] cbuf,int off,int len) throws IOException {
init();
return internalIn2.read(cbuf, off, len);
}
}
存放信息使用的类
class Info implements Comparable<Info>{
String province;
int infected = 0;
int suspected = 0;
int dead = 0;
int cured = 0;
@Override
public int compareTo(Info o) {
// TODO Auto-generated method stub
Comparator<Object> com = Collator.getInstance(java.util.Locale.CHINA);
return com.compare(this.province, o.province);
}
public boolean equals(Object o) {
Info t = (Info)o;
return this.province.equals(t.province);
}
}
单元测试
log内容
测试1
@Test
void test1() throws FileNotFoundException, IOException { //无参数情况
String args[]= {"list", "-log", "D:/log/", "-out", "D:/output1.txt"};
InfectStatistic.main(args);
}
结果
测试2
@Test
void test2() throws FileNotFoundException, IOException { //省份参数无记录情况
String args[]= {"list", "-log", "D:/log/", "-out", "D:/output2.txt","-province","湖南"};
InfectStatistic.main(args);
}
结果
测试3
@Test
void test3() throws FileNotFoundException, IOException { //带日期参数
String args[]= {"list", "-log", "D:/log/", "-out", "D:/output3.txt","-date", "2020-01-21"};
InfectStatistic.main(args);
}
结果
测试4
@Test
void test4() throws FileNotFoundException, IOException { //带类型参数
String args[]= {"list", "-log", "D:/log/", "-out", "D:/output4.txt","-type","cure"};
InfectStatistic.main(args);
}
结果
测试5
@Test
void test5() throws FileNotFoundException, IOException { //带多个省份参数
String args[]= {"list", "-log", "D:/log/", "-out", "D:/output5.txt","-province","福建","全国"};
InfectStatistic.main(args);
}
结果
测试6
@Test
void test6() throws FileNotFoundException, IOException { //同时带日期和类型参数
String args[]= {"list", "-date", "2020-01-25", "-log", "D:/log/", "-out", "D:/output6.txt","-type","cure"};
InfectStatistic.main(args);
}
结果
测试7
@Test
void test7() throws FileNotFoundException, IOException { //同时带日期和省份参数
String args[]= {"list", "-date", "2020-01-22", "-log", "D:/log/", "-out", "D:/output7.txt","-province","福建"};
InfectStatistic.main(args);
}
结果
测试8
@Test
void test8() throws FileNotFoundException, IOException { //同时带日期、无记录省份、类型参数
String args[]= {"list", "-log", "D:/log/", "-out", "D:/output8.txt","-type","cure","-province","福建","江苏"};
InfectStatistic.main(args);
}
结果
测试9
@Test
void test9() throws FileNotFoundException, IOException { //同时带日期省份类型参数
String args[]= {"list", "-date", "2020-01-22", "-log", "D:/log/", "-out", "D:/output9.txt","-type","sp","-province","福建"};
InfectStatistic.main(args);
}
结果
测试10
@Test
void test10() throws FileNotFoundException, IOException { //同时带日期多个类型多个省份参数
String args[]= {"list", "-date", "2020-01-22", "-log", "D:/log/", "-out", "D:/output10.txt","-type","ip","dead","-province","福建","全国"};
InfectStatistic.main(args);
}
结果
单元测试覆盖率及性能优化
单元测试覆盖率
在范例给的log基础上添加了其他的情况 增加覆盖率
性能测试
代码规范
心路历程与收获
《构建之法》中提到:关于工程师与程序员的区别是关于代码的规范程度。没读这本书之前,并不太懂软件工程的概念,只是认为软件的核心的就是代码,那么软件工程的核心就是写代码的程序员如何写好代码。在一开始的读书过程中,我颠覆了以往的观念,但后来其实想想也并无大错,其实软件工程的一系列方法,都是为了让程序员更好的去完成工作。软件这门工程,也如同盖楼一样,一个人的能力强大, 最多让某个结构更加坚固,但是软件工程着眼的是整个工程,并不简简单单局限于某个点某个面。我们所罗列的方法与思想,都是为了整个工程流程而服务的。这才是软件工程的核心所在。这次的作业虽然功能很少,但是还是花了我不少的时间。大多数时间是花在强制自己按规范操作,熟悉规范的软件开发流程。
第一次作业中技术路线图相关的5个仓库
java学习+面试指南
一份涵盖大部分Java程序员所需要掌握的核心知识。帮助复习和巩固java知识,为之后的学习工作打好基础。
HTML,CSS,and JavaScript
最流行的HTML、CSS和JavaScript框架,用于在web上开发响应性强、移动优先的项目。
SSM框架
手把手教你整合最优雅SSM框架:SpringMVC + Spring + MyBatis。
Java后端
从Java基础、JavaWeb基础到常用的框架再到面试题都有完整的教程,几乎涵盖了Java后端必备的知识点。
spring boot demo
是一个用来深度学习并实战 spring boot 的项目。