1.前言
工作中难免会遇到维护别人代码的情况,那么首先就得看懂别人写的代码。如果对方写的代码混乱臃肿,维护成本必然很高,如果对方写的代码优雅清晰,那维护的人看起来必然心情愉悦。正所谓“前人栽树,后人乘凉;
前人埋坑,后人骂娘”。
文章图片
代码首先是给人看的,其次才是给机器看到,如何编写出任何人都看到懂的代码?答案是制定规范!
每个公司都会有自己的编码规范,但是往往的情况是赶项目进度或者懒惰或者个人水平习惯等原因,加上没有code review,最后代码就写的千奇百怪了。原因就在于规范是有了,但是没人遵守。所以,编码规范需要强制执行,交给工具来强制执行。
本文将通过介绍java静态代码检查工具PMD、阿里巴巴p3c开源项目到最后编写自定义编码规约来学习如何规范代码的编写。
2.PMD静态代码扫描
2.1.PMD官网
https://pmd.github.io/2.2.概述
PMD是一种开源分析Java代码错误的工具。它通过静态分析获知代码错误。也就是说,在不运行Java程序的情况下报告错误。PMD附带了许多可以直接使用的规则,利用这些规则可以找出Java源程序的许多问题,例如:
- 潜在的bug:空的try/catch/finally/switch语句
- 未使用的代码:未使用的局部变量、参数、私有方法等
- 可选的代码:String/StringBuffer的滥用
- 复杂的表达式:不必须的if语句、可以使用while循环完成的for循环
- 重复的代码:拷贝/粘贴代码意味着拷贝/粘贴bugs
- 循环体创建新对象:尽量不要再for或while循环体内实例化一个新对象
- 资源关闭:Connect,Result,Statement等使用之后确保关闭掉
2.3.工作原理
PMD的核心是JavaCC解析器生成器。PMD结合运用JavaCC和EBNF(扩展巴科斯-诺尔范式,Extended Backus-Naur Formal)语法,再加上JJTree,把Java源代码解析成抽象语法树(AST,Abstract Syntax Tree)
从根本上看,Java源代码只是一些普通的文本。不过,为了让解析器承认 这些普通的文本是合法的Java代码,它们必须符合某种特定的结构要求。这种结构可以用一种称为EBNF的句法元语言表示,通常称为“语法” (Grammar)。JavaCC根据语法要求生成解析器,这个解析器就可以用于解析用Java编程语言编写的程序。
2.4.规则分类
- 最佳实践:公认的最佳实践的规则。
- 代码风格:这些规则强制执行特定的编码风格。
- 设计:帮助您发现设计问题的规则。
- 文档:这些规则与代码文档有关。
- 容易出错的规则:用于检测被破坏的、非常混乱的或容易发生运行时错误的结构的规则。
- 多线程:这些规则在处理多个执行线程时标记问题。
- 性能:标记存在性能问题的代码的规则。
- 安全:显示潜在安全缺陷的规则。
- https://pmd.github.io/pmd-5.4...
- https://testerhome.com/topics...
- http://www.w3school.com.cn/xp...
https://github.com/alibaba/p3c3.2.概述
阿里巴巴p3c项目包含三个部分:
- p3c-pmd,提供大部分规则实现,基于PMD框架开发,如果想实现自己的规则,可以基于该模块开发(该模块基于maven编译打包)
- IntelliJ IDEA插件,即idea-plugin模块(该模块基于gradle编译打包)
- Eclipse插件,即eclipse-plugin,本文不介绍
传送门:https://github.com/alibaba/p3...4.基于p3c编写自定义编码规则 4.1.自定义规则
假设现在需要开发这么一个规则:方法请求参数列表不允许超过(含)5个
4.2.开发步骤
4.2.1.找出问题代码,使用pmd图形化工具解析成抽象语法树 代码示例:
package org.p3c.demo;
public class Demo {public void methodA(int a) {}public void methodB(int a, int b, int c, int d, int e) {}
}
将源码放入Source Code框,点击Go按钮,解析结果显示在左下框
文章图片
4.2.2.分析抽象语法树 可以看到,整棵树的根节点是CompilationUnit,即编译单元,代表每个java源文件。我们首先要找到所有的方法声明,根据树节点名称大概也能看出来是MethodDeclaration,点击相应的节点,看看光标是否定位到源码方法声明位置。
仔细分析MethodDeclaration节点,可以看到他有以下几个直接子节点:ResultType、MethodDeclarator、Block,即返回类型、方法声明、方法体
【别再写垃圾代码了(试试阿里巴巴 Java 开发插件,打造你的团队专属风格。。。)】
文章图片
MethodDeclarator是我们想找的节点XPATH表达式可以这么写:
//CompilationUnit//MethodDeclarator
验证表达式是否正确,将它写到PMD图形界面XPATH Query框中,点击Go按钮
文章图片
接下来,我们需要找到每个方法对应的参数列表,参数列表节点是方法节点的直接子节点,完整XPATH表达式为:
//CompilationUnit//MethodDeclarator/FormalParameters
文章图片
获取到参数列表节点后,我们查看该节点的属性,找出参数个数的属性,观察可以发现是ParameterCount属性。
到现在为止,抽象语法树已经分析完,我们知道这么找出代码中参数列表大于等于5个的方法了。
4.2.3.p3c-pmd项目编写自定义代码规则 打开阿里p3c-pmd工程,开始编写我们的自定义规则。
阿里已经写了很多规则,我们现在要编写的规则属于面向对象范畴,可以把规则写到opp包下,新建一个规则类MethodParameterCountRule,继承自AbstractAliRule,重写 visit方法:
文章图片
package com.alibaba.p3c.pmd.lang.java.rule.oop;
import com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
import java.util.List;
/**
* 方法参数列表个数不宜过长
*
* @auther qingjian.wu
* @create 2018-01-27 14:59
*/
public class MethodParameterCountRule extends AbstractAliRule{private static final String METHOD_XPATH = "//MethodDeclarator";
private static final Integer PARAMETER_COUNT_LIMIT = 5;
@Override
public Object visit(ASTCompilationUnit node, Object data) {
try {
// 找到所方法节点
List methodNodes = node.findChildNodesWithXPath(METHOD_XPATH);
if (methodNodes != null && methodNodes.size() > 0) {
for (Node methodNode : methodNodes) {
// 找到每个方法的参数列表声明
List formalParameters = methodNode.findChildrenOfType(ASTFormalParameters.class);
if (formalParameters.get(0).getParameterCount() >= PARAMETER_COUNT_LIMIT) {
// 违反规则提示信息,第二个参数是提示信息位置,第三个参数是提示信息key,第四个参数用来替换提示信息
// 中的占位符,这里获取的节点image属性就是方法名称
addViolationWithMessage(data, methodNode,
"java.oop.MethodParameterCountRule.violation.msg",
new Object[]{methodNode.getImage()});
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return super.visit(node, data);
}
}
4.2.4.p3c-pmd项目配置规则 将编写好规则配置到ali-oop.xml文件中
文章图片
1
4.2.5.p3c-pmd项目编写提示信息 上两步使用的提示信息和规则信息需要编写到message.xml配置文件中,message_en.xml中是英文提示,这里就先不演示了
文章图片
4.2.6.单元测试 编写测试样例,将要测试的源代码写到test目录对应的xml文件中
推荐一个 Spring Boot 基础教程及实战示例:
https://github.com/javastacks...
文章图片
0
编写单元测试
文章图片
运行单元测试,因为样例代码中methodB不符合规范,但是我们预期问题个数写的是0,所以单元测试会不通过:
文章图片
4.3.配置插件
4.3.1.p3c-pmd打包安装到本地maven仓库 先把用不到的插件maven-javadoc-plugin和maven-gpg-plugin注释掉,然后运行mvn命令:
mvn -DskipTests=true clean install
4.3.2.idea-plugin项目打包插件 idea-plugin项目基于gradle构建,配置根目录下build.gradle,让构建使用本地私有maven仓库构建
文章图片
然后运行开始gradle构建:
clean buildDependents build
打包成功后会在
idea-plugin\p3c-idea\build\distributions\
目录下生成Alibaba Java Coding Guidelines-1.0.0.zip文件,这个就是我们加入了自己拓展阿里开发规约的插件,IDEA中安装此插件Settings->Plugins->Install plugin from disk
文章图片
4.3.3.IDEA中使用编码规约插件 安装完插件重启IDEA,用之前的代码测试下插件是否生效。
右键点击“编码规约扫描”
文章图片
结果:
文章图片
5.Maven打包加入PMD校验 到目前为止,我们已经做到了能在开发阶段实时校验自己的代码了,最后我们需要把规约检查加入到代码打包中,这样才能做到部署到生产环境的代码都是符合规范的,如果不符合规范,打包会失败。
考虑到大多数项目使用maven管理,可以把自定义pmd规则整合到maven,这样就可以使用maven校验代码规则了
在maven项目中加入pmd插件,配置插件在package阶段执行。通常我们的项目都有一个公共的父pom,那将插件加入到父pom中就行
org.apache.maven.plugins
maven-pmd-plugin
3.8
rulesets/java/ali-comment.xml
rulesets/java/ali-concurrent.xml
rulesets/java/ali-constant.xml
rulesets/java/ali-exception.xml
rulesets/java/ali-flowcontrol.xml
rulesets/java/ali-naming.xml
rulesets/java/ali-oop.xml
rulesets/java/ali-orm.xml
rulesets/java/ali-other.xml
rulesets/java/ali-set.xml
true1
package
check
com.alibaba.p3c
p3c-pmd
1.3.3
如果存在不符合规范代码打包将失败:
文章图片
关于maven pmd插件更详细介绍参考官网
6.总结 本文篇幅确实有点长,看懂需要有点耐心。不过其实也挺简单,关键点就是分析抽象语法树,找出问题代码节点,剩下的工作就很简单了。
PMD也有局限性,比如只能校验java源文件,对于XML等配置规约就没辙了。还有最最重要的,代码逻辑等关键性问题是没法校验的,也没法做。PMD只是一定程度上规范了我们的代码,要写出优雅的代码,还得多思考多实践呐。
来源:blog.csdn.net/u014513883/article/details/79186893
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
推荐阅读
- Spring Authorization Server 0.2.3发布,放出联合身份DEMO
- 分布式|面试官(ZooKeeper分布式锁实现,你了解了吗())
- java|面试官: 说说看, 什么是 Hook (钩子) 线程以及应用场景?
- java|面试官(ZK(ZooKeeper)分布式锁实现,你了解了吗())
- Java|面试官问(说说你对ZooKeeper集群与Leader选举的理解())
- 字符串|深入正则表达式(3):正则表达式工作引擎流程分析与原理释义
- 与君共勉|【数据结构与算法】最小生成树与最短路径问题
- java|对数器验证算法正确性----bug寻找,文章中含有测试源码
- 区块链|教程丨三分钟教你制作专属NFT智能合约