第四周作业之wcPro核心模块的实现

第四周作业之wcPro核心模块的实现

一、基本任务:代码编写+单元测试

小组github地址

https://github.com/SkateCloud/wcPro

PSP表格

PSP2.1 PSP阶段 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 60
Estimate 估计任务需要多少时间 30 60
Development 开发 120 180
Analysis 需求分析 20 30
Design Spec 生成设计文档 20 30
Design Review 设计复审 20 30
Coding Standard 代码规范 30 10
Design 具体设计 30 50
Coding 具体编码 30 40
Code Review 代码复审 30 40
Test 测试 50 10
Reporting 报告 70 240
Test Report 测试报告 30 100
Size Measurement 计算工作量 20 60
Postmortem 总结 20 80
  合计 280 480

接口设计

  • 接口描述

本人负责的是核心模块,即对输入的文件读取后的结果进行单词排序并存入List结构中准备输出

  • 设计思路

对从输入模块获取的数据存入hashMap中,再将Map结构转变成List结构进行单词排序,为输出模块准备接口

  • 实现过程

先使用Map<String, Integer>结构对输入模块传来的数据进行存储.

 HashMap<String,Integer> words = new HashMap<>();
        String str = readFile(args[0]);
        {
            int state = 0;
            int beginIndex = -1;
            for (int i = 0; i <= str.length(); ++i) {
                char ch = i == str.length() ? ‘ ‘ : str.charAt(i);
                boolean isWordChar = (‘a‘ <= ch && ch <= ‘z‘) || (‘A‘ <= ch && ch <= ‘Z‘) || ch == ‘-‘;
                if (state == 0 && isWordChar && ch != ‘-‘) {
                    beginIndex = i;
                    state = 1;
                } else if (state == 1 && !isWordChar) {
                    String word = str.substring(beginIndex, i).toLowerCase();
                    words.put(word, words.getOrDefault(word, 0) + 1);
                    state = 0;
                }
            }
        }

由于外部存储机构使用的是Map.Entry<String, Integer>,不便于排序等操作,所以将map转化为List结构,进行排序

 List<Map.Entry<String, Integer>> list = new ArrayList<>();
        list.addAll(words.entrySet());
        list.sort((lhs, rhs) -> {
            int cmp = -lhs.getValue().compareTo(rhs.getValue());
            if (cmp != 0) return cmp;
            else return lhs.getKey().compareTo(rhs.getKey());
        });

测试设计

保证设计的测试用例应至少覆盖函数中所有的可执行语句,同时主要空数组、最差情况、词频排序、字母排序、两者混合等各种情况设计测试用例。

单元测试

使用测试脚本进行单元测试,过程如下

单元测试效果良好,没有报错

小组贡献

我们小组齐心协力, 攻克难关,积极讨论,指出问题,我认为我的小组贡献分是0.4

二.扩展任务:静态测试

1. 代码规范

我选择了代码风格规范中:断行与空白的{}行、分行、命名、下划线、大小写;

代码设计规范中:函数、错误处理、new和delete、类型继承,模块化

我的编程习惯与以上附录中所述规范大致相同。而在其他如代码审查等重要规范上有待提高。

2. 同组分析

我分析了自己的代码,缩进、断行风格整洁,命名简单明了,逻辑清晰易读,但在代码设计规范上,模块化不足,不易于进行团队的coding工作,经常在git操作上发生冲突.

最后决定将团队代码进行整合重构,重构任务由我完成,故最终贴出组长的重构代码

public class wordcount {
    public static void main(String[] args) {
        long t1 = System.currentTimeMillis();
        new wordcount().start(args);
        long t2 = System.currentTimeMillis();
        long dt = t2 - t1;
        System.out.println(("Elapsed " + dt + "ms"));
    }

    private void start(String[] args) {
        HashMap<String,Integer> words = new HashMap<>();
        String str = readFile(args[0]);
        {
            int state = 0;
            int beginIndex = -1;
            for (int i = 0; i <= str.length(); ++i) {
                char ch = i == str.length() ? ‘ ‘ : str.charAt(i);
                boolean isWordChar = (‘a‘ <= ch && ch <= ‘z‘) || (‘A‘ <= ch && ch <= ‘Z‘) || ch == ‘-‘;
                if (state == 0 && isWordChar && ch != ‘-‘) {
                    beginIndex = i;
                    state = 1;
                } else if (state == 1 && !isWordChar) {
                    String word = str.substring(beginIndex, i).toLowerCase();
                    words.put(word, words.getOrDefault(word, 0) + 1);
                    state = 0;
                }
            }
        }

        List<Map.Entry<String, Integer>> list = new ArrayList<>();
        list.addAll(words.entrySet());
        list.sort((lhs, rhs) -> {
            int cmp = -lhs.getValue().compareTo(rhs.getValue());
            if (cmp != 0) return cmp;
            else return lhs.getKey().compareTo(rhs.getKey());
        });

        try (FileWriter fout = new FileWriter("result.txt")) {
            int maxsz = Math.min(list.size(), 100);
            for (int i = 0 ; i < maxsz; ++ i) {
                Map.Entry<String, Integer> item = list.get(i);
                fout.write(item.getKey());
                fout.write(‘ ‘);
                fout.write(item.getValue().toString());
                if (i != maxsz - 1)
                    fout.write(‘\n‘);
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

    private String readFile(String path) { // 读文件
        try {
            byte[] encoded = Files.readAllBytes(Paths.get(path));
            return new String(encoded, "UTF-8");
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

}

3. 静态代码检查工具

使用的是IDEA的插件Ant Build中的检错功能

Ant Build是一个Java自动化生成工具,其检错功能用来检查类或者jar文件,用来发现可能的问题。检测完成之后会生成一份详细的报告,借助这份报告可以找到潜在的bug.

检测范围

  • 常见代码错误,序列化错误
  • 可能导致错误的代码,如空指针引用
  • 国际化相关问题:如错误的字符串转换
  • 可能受到的恶意攻击,如访问权限修饰符的定义等
  • 多线程的正确性:如多线程编程时常见的同步,线程调度问题。
  • 运行时性能问题:如由变量定义,方法调用导致的代码低效问题

4. 扫描结果

检测结果在右上角,可以看出仅有少量警告,根据IDEA红线标注可发现大多是声明方式不是按照目前使用的java标准,没有发生内存泄露等问题.

5. 小组代码问题说明

  • 由于进行了整合重构,所以模块化程度降低,不易维护,但程序执行效率上升
  • 异常处理的不够全面,应该覆盖大部分的一场情况,以便于检查与调试

三. 高级任务:性能测试和优化

设计,评审,优化

选择10kb,50kb,182kb大小的txt文件进行测试,程序处理时长如下:

      输入输出:1ms,1ms,2ms

      单词统计:20ms,150ms,540ms

      词频排序:6ms,8ms,10ms

  单词统计时间与文件大小呈线性相关,其他两个模块占比较小,故程序性能主要受到文件大小影响。组内共同对代码结构和细节进行详细审查并与其他组程序对比,整理得到如下观点:

    1.整合重构是正确的,不仅增加了代码的可读性和规范性,还大幅增加了程序的性能

    2.将大部分功能模块聚集在一个类方法中,虽然会导致代码耦合度增高,不易于团队维护和再开发,但是减少了模块间相互调用的开销和随之产生的内存开销

小结

通过基本任务、扩展任务、到高级任务的完成以及中间遇到的许多困难,体现出了软件测试对于软件开发的重要性。在开发过程中,使用静态测试工具实时地检测自己的代码,可以改正自己不良的编程习惯,更能防患于未然,减少出现bug的可能;对自己的模块进行单元测试,可以保障自己代码的正确性,更是对其他开发成员和整个任务的负责,使软件开发能够一步一个脚印地稳定开展;对性能的分析与测试,能使软件的质量进一步提高,同事能总结开发经验,使自己设计的模块更加高效。

原文地址:https://www.cnblogs.com/skatecloud/p/8748016.html

时间: 2024-12-17 00:51:06

第四周作业之wcPro核心模块的实现的相关文章

第四周作业

第四周作业 1.复制/etc/skel目录为/home/tuser1,要求/home/tuser1及其内部文件的属组和其它用户均没有任何访问权限. (1)复制/etc/skel目录为/home/tuser1 [[email protected] ~]# cp -r /etc/skel/ /home [[email protected] ~]# mv /home/skel /home/tuser1 [[email protected] ~]# ll -a /home/tuser1/ total 2

核心模块

核心模块Path 作用:用于帮助程序员来操作硬盘上的路径. 核心模块注意点:当引用核心模块的时候直接require('模块名'),不需要加任何路径或者后缀. Path中的常用API: dirname(路径): //获取传入路径中文件的路径 basename(路径): //如果不传入任何参数:直接获取到传入路径中文件的全名称(文件名+扩展名) //如果传入文件对应的后缀,会将后缀名去掉(传错与不传相同) extname(路径): //获取传入路径中文件的扩展名 join(): //将多个路径组装成

【Nginx】核心模块ngx_events_module

核心模块ngx_events_module是一个专门用于管理事件模块的模块.它的实现很简单,下面是该模块的定义: ngx_module_t ngx_events_module = { NGX_MODULE_V1, &ngx_events_module_ctx, /* module context */ ngx_events_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ NULL, /* init mast

[NodeJS]核心模块--Events

Events是Node中的一个很重要的核心模块,Stream, 网络,文件系统统统都是继承自这个模块. Streams模块就是继承自EventEmitter,所以说弄明白Events模块,特别是EventEmitter对象, 对于理解Node中的很多模块都是有好处的. Stream非常擅长处理数据,无论是读,写或者是转换.比如,你可以用Stream接收数据库中的数据,将其流出到csv的流中,导出成为csv格式. 接着你可以再传入一个http请求(也是一种流)将数据再流入到http流中,这样就可以

解题报告——2018级2016第二学期第四周作业 (2的幂次方)

解题报告——2018级2016第二学期第四周作业 题目: 描述 任何一个正整数都可以用2的幂次方表示.例如:137=27+23+20. 同时约定方次用括号来表示,即ab 可表示为a(b). 由此可知,137可表示为:2(7)+2(3)+2(0) 进一步:7= 22+2+20   (21用2表示) 3=2+20 所以最后137可表示为: 2(2(2)+2+2(0))+2(2+2(0))+2(0) 又如:1315=210 +28 +25 +2+1 所以1315最后可表示为: 2(2(2+2(0))+

node.js学习笔记5——核心模块1

Node.js核心模块主要内容包括:(1)全局对象 (2)常用工具 (3)事件机制 (4)文件系统访问 (5)HTTP服务器与客户端 一: 全局对象 Node.js中的全局对象是global,所有的全局变量(除了global本身以外)都是global的属性. global 最根本的作用是作为全局变量的宿主. 全局变量的条件: (1)在最外层定义的变量; (2)全局对象的属性: (3)隐式定义的变量(未定义直接赋值的变量(strict模式下不可以)) 在Node.js中不可能在最外层定义变量,因为

android第四周作业笔记

第四周作业要求如下 .....看了一下作业要求后,然后做了几周后.....老师....你这是玩我是吧?!你绝壁在玩我?! 算了,多说无益,来看看我们江大婶的做法吧 首先是MainActivity.java package cn.edu.shu.cs.android.experiment04; import android.app.ActionBar; import android.app.ActionBar.Tab; import android.app.Activity; import and

网页搜索核心模块架构重构

X模块是百度网页搜索的核心模块,与其他系统接口多,逻辑复杂,代码陈旧.长年密集的新特性开发导致留下了大量的技术债.我们在不影响新特性开发的情况下,在设计层面.编码层面重构了X模块架构代码,在代码可维护性.内存使用和运行效率上都取得了显著成果. 转:http://www.infoq.com/cn/presentations/architecture-reconstruction

【Nginx核心模块】线程池模块

本节研究Nginx中线程池模块的相关实现: 总体说明 (1)线程池模块属于核心模块,因此其配置内存ngx_thread_pool_conf_t将会预先申请好:ngx_thread_pool_conf_t中主要管理各个线程池结构: (2)在ngx_thread_pool_init_worker和 ngx_thread_pool_exit_worker分别会创建每一个线程池和销毁每一个线程池: 线程池模块 ngx_module_t ngx_thread_pool_module = { NGX_MOD