第一次个人编程作业
PSP
PSP2.1 | Personal Software Process Stages |
预估耗时(min) | 实际耗时(min) |
---|---|---|---|
Planning | 计划 | 54 | 54 |
Estimate | 估计这个任务需要多少时间 | 54 | 54 |
Development | 开发 | 792 | 880 |
Analysis | 需求分析 (包括学习新技术) |
90 | 90 |
Design Spec | 生成设计文档 | 54 | 40 |
Design Review | 设计复审 | 54 | 20 |
Coding Standard | 代码规范 (为开发制定合适的规范) |
27 | 10 |
Design | 具体设计 | 108 | 100 |
Coding | 具体编码 | 189 | 360 |
Code Review | 代码复审 | 60 | 60 |
Test | 测试 (自我测试,修改,提交修改) |
189 | 200 |
Reporting | 报告 | 54 | 54 |
Test Report | 测试报告 | 18 | 18 |
Size Measurement | 计算工作量 | 9 | 9 |
Postmortem & Process Improvement Plan |
事后总结 并提出过程改进计划 |
27 | 27 |
合计 | 900 | 988 |
解题思路
**step 1. **利用正则表达式提取姓名和手机号码, 并将其从原字符串中去除
**step 2. ** (Level 1) 利用中国省市区街道四级联动json数据逐级匹配地址,对于缺字的情况,取前两个字当作关键词匹配。对于缺级的情况,遍历上一级所有子级的子级匹配。虽然总数据量较大,但是实际上每次分级之后可以少检索很多数据。
**step 3. ** (Level 2) 利用正则表达式分割剩余的详细地址
**step 4. ** (Level 3) 调用高德Api
**step 5. ** 使用Moshi库将结果对象转换成Json输出
设计实现过程
数据类
类名 | 说明 | 属性 |
---|---|---|
Data | 数据 | provinces |
Result | 结果 | name, phone, address |
Province | 省级 | name, cities |
City | 地级 | name, areas |
Area | 县级 | name, streets |
Street | 街道 | name |
工具类
类名 | 作用 |
---|---|
FileUtil | 读取和写入文件 |
JsonUtil | 转换对象和Json字符串 |
Trimmer | 处理输入样例 |
主要函数
函数名 | 说明 |
---|---|
void Data.build() | 用json数据生成所需对象 |
void trimName() | 切去姓名 |
void trimPhone() | 切去手机号 |
void trimProvince() | 切去省级 |
void trimCity(List<City>) | 切去地级 |
void trimArea(List<Area>) | 切去县级 |
void trimStreet(List<Street>) | 切去街道 |
void trimDetail() | 切分详细地址 |
单元测试 (with JUnit 5)
设计
这个题输入比较稳定,只是有可能缺失某几级地址,可以考虑为每个缺失设计一个caseN()测试函数,手动输入样例和答案,例如:
@Test
public void case15() {
String testCase = "2!甘鞋,甘肃兰州西固区西柳沟街道18629411660什么花园.";
String name = "甘鞋";
String phone = "18629411660";
String[] address = new String[]{
"甘肃省",
"兰州市",
"西固区",
"西柳沟街道",
"",
"",
"什么花园"
};
resultTest(testCase, name, phone, address);
}
用resultTest函数验证正确性:
private void resultTest(String testCase, String expectedName, String expectedPhone, String[] expectedAddress) {
Result result = new Trimmer(testCase).trim().toResult();
String message = testCase + System.lineSeparator() + result.toString();
Assert.assertEquals(message, expectedName, result.getName());
Assert.assertEquals(message, expectedPhone, result.getPhone());
Assert.assertArrayEquals(message, expectedAddress, result.getAddress().toArray());
}
如果结果与预期有误,则调用assertEquals输出错误信息,方便调试:
测试结果
一共设计了15个不同情况的case,经过疯狂调试,终于全部通过。
完整单元测试代码
测试覆盖率
分割地址用的主要是Trimmer类,除了getter和setter都覆盖到了。其余没覆盖到的也主要是getter和setter。
异常处理
异常主要发生在Trimmer类的方法里,主要是由于输入错误导致的,这样的异常不好正确处理,这里简单地将trim方法包裹在try代码块里,执行时判断输入是否符合要求,如果不符合,中断执行,并直接返回一个空的结果,避免了程序直接退出。
@Test
public void exceptionCase1() {
String testCase = "甘鞋,甘肃兰州西固区西柳沟街道18629411660什么花园.";
resultTest(testCase,"","",new String[]{});
}
代码分析 (with Codacy)
根据提示消除了了所有Issue.
性能测试 (with JProfiler)
程序中最占内存的是解析json数据构造出来的String对象,最耗时的操作是解析Json数据。为了提高效率,可以考虑把Json解析器换成FastJson。
收获
这一次还是收获满满的,学会了很多东西:
- 用JUnit做单元测试;
- 用JProfiler做性能分析;
- 用Codacy做代码分析;
- 用Gradle构建项目,并把所需依赖打包到Jar文件里;
其中最有用的要数单元测试了,可以很方便的测试出Bug来,并修改完代码之后可以反复运行,效率很高,相比以前手动测试,节省了不少时间。代码分析工具可以检测出代码中不合理的地方,并给出修改提示,按照提示修改代码,可以提高代码的可读性和健壮性。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· DeepSeek火爆全网,官网宕机?本地部署一个随便玩「LLM探索」
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 上周热点回顾(1.20-1.26)
· 【译】.NET 升级助手现在支持升级到集中式包管理