一种基于两阶段框架的Java方法名推荐方法
技术领域
本发明涉及软件工程领域。更具体地,涉及一种基于两阶段框架的Java方法名推荐方法。
背景技术
随着信息化浪潮的不断推进以及互联网时代的到来,人们生活中的衣食住行各个方面都越来越离不开软件。由于来自人们生活中层出不穷的软件需求,现代软件的功能日趋复杂,模块数目日渐增多,导致了软件的复杂度正不断提高。面对日益复杂的软件,软件的维护难、成本高成为了目前的一大难题。有调查称软件维护的成本大约占软件总成本的70%及以上,而导致维护成本高的重要原因是软件的可理解性低,开发人员往往要花费超过50%的精力在软件的代码的理解上。导致软件可理解性低的原因有很多,其中程序中命名不恰当的变量名、方法名、参数名等,往往是导致程序可理解性低的重要原因。
高质量的程序命名可以提高程序的可读性和可维护性,然而程序的命名是软件工程领域的一大难题。标识符命名是程序员必须完成的最困难的任务之一。在编程中,名称(即标识符)普遍存在于所有的程序概念中,例如类、方法和变量。在实际开发中,开发者常常写出不一致的程序命名,其中的原因往往有很多。除了开发者自身的素质外,比如没有一个统一的同义词表、不同协作的开发者之间相互冲突的命名风格等等。由此可见,程序的命名问题在软件的开发和维护中至为重要,但是由于其受到人为因素的影响,缺少统一的命名风格和约束,容易导致命名不一致的问题。
方法命名是程序命名任务中的一种。在实际的开发中,方法名常常被看做是方法体功能的简要描述。在实际开发中,方法名是开发人员理解程序或API行为的直观而重要的信息。因此,不一致的方法名会使程序更难理解和维护,甚至可能导致软件缺陷。开发者往往靠方法名来猜测方法的功能并调用对应的方法,如果方法名起的不好,容易导致开发者对于API的误用,进而导致软件缺陷的发生。
综上所述,为了提高软件的可维护性的同时降低软件的维护成本,软件工程领域急需一种方法来高效地推荐高质量的方法名,进而提高程序的可读性,降低开发人员在理解代码时所花费的时间和精力,最终提高软件的可维护性。
发明内容
本发明的目的在于提供一种基于两阶段框架的Java方法名推荐方法,提高项目代码的可读性和可理解性的同时,帮助开发者通过方法名快速了解方法所实现的功能,进而降低软件维护的成本,提高软件开发的效率。
为达到上述目的,本发明采用下述方法:
基于两阶段框架的Java方法名推荐方法,在进行数据预处理后,包括:
第一阶段:方法分类阶段。
第二阶段:方法名生成阶段。
具体的,在数据预处理过程中,对于输入的Java方法的特征,采用启发式的规则过滤掉getter/setter方法以及delegations方法,其中getter是专门用来获取Java类中非静态私有属性的方法,而setter方法是专门用来给Java类中非静态私有属性赋值的方法,在Java语言的编程规范中,getter方法和setter都有固定的格式。其中delegations方法中仅仅有一行程序语句,且该条程序语句调用了其所在类中的其他方法。
进一步的,读取Java程序源代码并解析得到方法列表,其中判断方法是否为getter方法的规则为如果一个方法中只有一行代码语句且该方法返回了类中的私有非静态属性的值,那么该方法就为getter方法,该方法方法体格式描述为return this.${方法所在类中非静态私有属性};或者是return${方法所在类中非静态私有属性};。其中判断方法为setter方法的规则为如果一个方法中仅仅只有一行代码语句且该语句的功能是给方法所在类中的非静态属性赋值,该方法方法体格式描述为this.${方法所在类中非静态私有属性}=赋值;或者为this.${方法所在类中非静态私有属性}=赋值;
较佳的,判断一个方法是否是delegations方法的规则如下,如果一个方法中仅仅只有一行代码语句且该语句调用了该方法所在类中的其他方法,那么该方法就是delegations方法,其该方法方法体格式描述为return${方法所在类中的其他方法的方法名}(参数列表);或者为${方法所在类中的其他方法的方法名}(参数列表);。
进一步的,为getter/setter方法命名,其中对于getter方法的生成的方法名格式为get${方法所在类中非静态私有属性,其中首字母大写},其中对于setter方法的生成方法名格式为set${方法所在类中非静态私有属性,其中首字母大写}。其中对于delegations方法生成的方法名格式为${方法所在类中的其他方法的方法名}。
具体的,在第一阶段方法分类过程中,采用前馈神经网络FastText对Java方法分类,其中分类输入的数据采用的是Java方法体的标记流,其中标记流是采用词法分析得到的键值对,键值对是包含了类型和标记。分类采用方法的对应方法名的前缀作为分类依据,通过分类的方法来预测方法名的前缀。
进一步的,特征在于输入fastText标记流格式由键值对组成,键值对由词法分析得到,例如对于给定的程序片段"int a;",分析得到的标记流为"[PrimitiveType,int,Variable,a]"。FastText根据方法名的前缀将Java方法分为5个类别,分别是方法名以特殊前缀"test"、"is"、"get"、"set"开头的方法,以及以其他前缀"others"开头的Java方法,在训练的过程中,特别地,采用bigram词级训练模型。
具体的,在第二阶段方法名生成过程中,针对方法名前缀开头的方法采用不同的方法名推荐方法。其中针对方法名以"test"、"is"、"get"、"set"等前缀开头的方法,采用启发式规则来为Java方法命名。启发式命名规则如下:对于已知方法分类器分类得到的前缀,从方法体中的标识符流中提取出现频率最高的标识符作为后缀,前缀和后缀通过驼峰命名法则来拼接得到Java方法名。
进一步的,提取方法在于提取方法所处的上下文,采用驼峰法则切分代码片段包括方法所在的类、方法体中的标识符、方法的参数列表以及返回值拼接得到方法的上下文,并将方法上下文特征输入到Recursive RNN模型中,进而预测得到Java方法名。recursiveRNN来生成对应的方法名,recursive RNN是一种基于编码器和解码器机制的特殊的seq2seq模型。该模型可以从方法所在的上下文中提取重要的特征并选择可能的标记来组成相应的方法名。本项目选择recursive RNN的主要原因是因为其将当前的输出作为下一次的输入,通过同时考虑已经生成的序列并结合当前输入的序列,其可以为解码器提供更为广阔的上下文来解释和输出下一个标记,所以其提高了生成方法名的语义连贯性。
如图4所示展示了Recursive RNN的架构。首先,对于输入上下文中的每一个标记首先被转化为one-hot向量,然后将其输入长短时记忆网络LSTM。该模型采用两个长短时记忆网络(LSTM),这两个网络都具有相同的结构。其中一个负责处理方法上下文的嵌入式表示,另外一个负责处理方法名标记流的嵌入式表示。方法上下文的嵌入式表示和方法名标记流的嵌入式表示通过拼接得到向量。向量被提交给密集层得到词表中每个单词被选中的可能性。该模型将预测得到的标记反馈给方法名序列。这个过程将会一直持续直到模型输出终止标记为止。
本发明的有益效果如下:
(1)本项目通过推荐高质量的Java方法名,可以帮助开发者在实际的开发中调用方法的时候可以通过方法名快速的了解方法的功能,减少在理解程序功能上所花费的精力,进而提高进一步的开发效率。
(2)由于开发者可以通过方法名更好的理解整个Java方法的功能,进而可以减少误用API的可能性的同时减少软件出现软件缺陷的可能性,进而提高整个软件代码的质量。
(3)在帮助开发者的同时,还可以节约软件开发在维护阶段的成本,提高软件整体的可理解性和可维护性。
(4)通过给开发者推荐高质量的方法名,还可以应对开发和维护阶段的人员变更问题,新参与进项目的开发者可以快速上手理解整个项目每个模块的功能,进而降低了整个项目的成本。
(5)由于高质量的Java方法名可以提高整个软件代码的质量,由于该项目的代码质量的提高,也间接提高了依赖于该项目的其他项目的质量。
附图说明
下面结合附图对本发明的
具体实施方式
作进一步详细的说明。
(1)图1为本发明表示总体方法的设计图。
(2)图2为本发明表示数据预处理流程图。
(3)图3为本发明表示基于两阶段框架的Java方法名推荐方法流程图。
(4)图4为本发明表示Recursive RNN模型架构图。
具体实施方式
为了更清楚的说明本发明,下面结合优选的实施案例和例图对本发明做进一步说明。附图中相似的部件以相同的附图标记进行表示。本领域技术人员应当理解,下面所具体描述的内容是说明性的而非限制性,不应以此限制本发明的保护范围。
首先,对本发明所揭示的技术方案的技术构思进行说明。现代软件的功能日趋复杂,面对日益复杂的软件,软件的维护难、成本高成为了目前的一大难题。软件维护的成本在软件总成本占最大的比重,而导致维护成本高的重要原因是软件的可理解性低,开发人员往往要花费大量精力在软件的代码的理解上。导致软件可理解性低的原因有很多。其中程序中命名不恰当的变量名、方法名、参数名等,往往是导致程序可理解性低的重要原因。开发者往往囿于项目的进度压力,将主要精力放在了程序功能的实现上,却忽略了程序的命名的重要性,导致在维护阶段要花大量的精力来理解程序的功能。
以下结合附图,详细说明本申请实施例提供的技术方案。
图1为发明实施例一种基于两阶段框架的Java方法名推荐方法的总体设计图。请参阅图1,本实施例提供一种基于两阶段框架的Java方法名推荐方法,包括:
环境配置:基于两阶段框架的Java方法名推荐方法的环境配置;
Git仓库数据挖掘:采集知名开源组织的下的Java项目仓库并解析提取得到高质量的Java方法;
基于两阶段框架的Java方法名推荐方法;基于两步神经网络来实现Java方法名的推荐,该过程主要包含了两个阶段,在预处理过程中,在这个阶段会为getter/setter方法以及delegations方法命名。第一阶段是方法分类阶段,在这个阶段会根据方法名的前缀来对Java方法进行分类。第二个阶段的Java方法名生成阶段,这个阶段的主要任务是主要包含两项,其一是针对以特定前缀开头的Java方法名采用启发式规则来生成Java方法名,其二是针对方法名以其他前缀开头的Java方法采用神经网络来生成Java方法名。
具体实施时,本实施例中环境配置实现。编译器版本为:Python版本为Python3.6,Java版本为JDK1.8。服务器采用ubuntu16.04.2。集成开发环境采用:PyCharm和IDEA。爬虫框架采用Scrapy。Java源代码解析框架采用Javaparser。FastText和Recursive RNN采用Pytorch实现。
具体实施时,如图2所示,本实施例中Git仓库数据挖掘实现,在爬取的过程中,部署在云服务器上的爬虫程序负责解析获取仓库的地址,并克隆下载仓库到本地,下载到本地后的代码仓库会被清洗得到程序的源代码文件,源代码会在后续被处理和解析。处理好的数据会被保存在云服务器上。由于GitHub有相应的反爬机制,其会防止过多和过快的访问次数,所以该爬虫采取了模拟请求头、停止等待等策略,以及令牌池的策略来解决GitHub的爬虫限制。GitHub的内部往往会通过简单的请求头来判断访问者是用户还是机器人,对于机器人网站后台往往存在相应的限制,为了能伪装成正常的用户来进行访问该网站,本项目将多个访问线程的请求头模拟成不同用户客户端的请求头。GitHub对于相同IP的访问次数的限制,为了解决该问题本项目采用设置延迟的方式来降低访问的频率,虽然这样会降低爬虫的爬取频率,但是却会防止该机制的限制。最后由于GitHub具有令牌机制,所谓的令牌机制即网站会对每个用户的权限有一定的限制,比如限制一个用户在一段时间内克隆仓库的频率。本项目首先构建令牌池,多个线程轮流使用令牌池中不同的令牌来完成对于网站的爬取。任务调度器负责创建和调度爬虫线程来完成对于GitHub的爬取,其首先将爬取的任务放入任务队列,然后分配这些任务给不同的线程,然后组织这些线程来加速对GitHub仓库的爬取。
进一步的,对于爬取的Git仓库,本项目首先遍历对应的Git仓库目录提取源代码,然后通过Java的语法解析库JavaParser来提取源代码对应的抽象语法树(AST),通过遍历抽象语法树来获取方法对应的方法名和方法体以及方法所在的上下文(包括方法所在类名、Java方法的参数列表、Java方法的返回值、Java方法体的实现代码)。
具体地,对于解析得到的Java方法,本项目将其解析为三种数据格式。第一种数据格式,是通过词法分析得到Java方法体中的每一个标记,其用于在基于两阶段框架的Java方法名推荐方法的预处理阶段,在该阶段其用于根据启发式规则生成Java方法名。第二种格式是通过词法分析将Java方法体解析为键值对的序列,其用于第二步根据不同方法名前缀对Java方法分类。第三种格式是提取Java方法的上下文(包括方法所在类名、Java方法的参数列表、Java方法的返回值、Java方法体的实现代码),其用于在第二步过程中生成方法名。
具体实施时,如图3所示。本实施案例基于两步神经网络Java方法名推荐方法实现。该方法的核心的思想是将针对不同的类别的方法的特性来推荐相应的方法名,首先通过前馈神经网络FastText对不同的方法进行分类,之后针对不同类别的方法分别采用不同的推荐算法来完成整个方法的推荐。在经历数据预处理阶段后,整个流程可以两个阶段,第一阶段是方法分类阶段,通过前馈的神经网络来针对不同前缀的方法名进行分类。第二阶段是方法命名阶段,对于一些方法名以特殊的前缀开头的方法,采用相应的启发式规则来生成方法名,而对于方法名以其他前缀开头的方法,本项目采用Recursive RNN来生成方法名。
具体的,在数据预处理阶段,如果一个方法是getter/setter或者是delegations方法,本项目输入数据格式1交给相应的启发式生成程序来为其生成相应的方法名,否则本项目将方法的数据格式2交给前馈网络分类器。分类器根据方法的不同方法名前缀将方法分成不同的类别,对于一些方法名以一些特殊前缀开头的方法比如(test、is、get、set),本项目将数据格式3交给相应的规则生成器,并采用一些启发式的规则来生成相应的方法名,而对于以其他前缀开头的方法,则将相关的数据格式3交给神经网络Recursive RNN来生成方法名。
进一步的,对方法进行分类预处理的主要目的是将适合用启发式规则生成方法名的特殊方法通过分类器识别出来。分类器可以针对不同的方法的方法名前缀(比如get、set、test、is)将方法分成多个类别。为了将方法名以特殊前缀命名的方法识别出来,本项目采用FastText来作为第一阶段的分类器,因为其在训练和测试两个阶段的速度都非常快,除此之外其还可以保持较高的分类准确性。
进一步的,第一阶段的分类器将方法主要分为了两类,其中第一类方法的方法名的前缀由特殊的前缀组成,而第二类方法的方法名没有特殊的前缀。因此本项目认为如果一个方法的对应方法名的前缀是"get"、"set"、"is"或者"test"那么该方法就是第一类方法。对于第一类方法,本项目采用启发式的规则来推荐方法名。而对于第二类方法,本项目采用Recursive RNN来生成对应的方法。
具体的,本项目提出了相应的启发式规则,首先对于第一类方法,本项目将这些方法的方法名看做是前缀和后缀的拼接,对于给定的方法体mb,本项目将其转化为的数据格式2并提取其中的标识符序列,本项目选择出现频率最高的后缀s。第一步通过分类得到的前缀是p,本项目将前缀和后缀通过驼峰命名法则拼接起来得到对应的方法名。
进一步的,对于第二类方法,本项目采用recursive RNN来生成对应的方法名,recursive RNN是一种基于编码器和解码器机制的特殊的seq2seq模型。该模型可以从方法所在的上下文中提取重要的特征并选择可能的标记来组成相应的方法名。本项目选择recursive RNN的主要原因是因为其将当前的输出作为下一次的输入,通过同时考虑已经生成的序列并结合当前输入的序列,其可以为解码器提供更为广阔的上下文来解释和输出下一个标记,所以其提高了生成方法名的语义连贯性。
本领域普通技术人员可以理解,实现上述发明方法中的全部或部分步骤是可以通过程序来进行实现。
以上所述仅为本申请的实施例而已,并不用于限制本申请。对于本领域技术人员来说,本申请可以有各种更改和变化。凡在本申请的精神和原理之内所作的任何修改、等同替换、改进等,均应包含在本申请的权利要求范围之内。