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 等应用之后确保敞开掉
此外,用户还能够本人定义规定,查看 Java 代码是否合乎某些特定的编码标准。例如,你能够编写一个规定,要求 PMD 找出所有创立 Thread 和 Socket 对象的操作。
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. 规定分类
- 最佳实际:公认的最佳实际的规定。
- 代码格调:这些规定强制执行特定的编码格调。
- 设计:帮忙您发现设计问题的规定。
- 文档:这些规定与代码文档无关。
- 容易出错的规定:用于检测被毁坏的、十分凌乱的或容易产生运行时谬误的构造的规定。
- 多线程:这些规定在解决多个执行线程时标记问题。
- 性能:标记存在性能问题的代码的规定。
- 平安:显示潜在平安缺点的规定。
2.5. 编写 PMD 自定义规定
- https://pmd.github.io/pmd-5.4…
- https://testerhome.com/topics…
- http://www.w3school.com.cn/xp…
3. 阿里巴巴 Java 开发规约插件 p3c
3.1.GITHUB 地址
https://github.com/alibaba/p3c
3.2. 概述
阿里巴巴 p3c 我的项目蕴含三个局部:
- p3c-pmd,提供大部分规定实现,基于 PMD 框架开发,如果想实现本人的规定,能够基于该模块开发(该模块基于 maven 编译打包)
- IntelliJ IDEA 插件,即 idea-plugin 模块(该模块基于 gradle 编译打包)
- Eclipse 插件,即 eclipse-plugin,本文不介绍
3.3. 阿里编码规约 IDEA 插件应用
传送门: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,即返回类型、办法申明、办法体
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<Node> methodNodes = node.findChildNodesWithXPath(METHOD_XPATH);
if (methodNodes != null && methodNodes.size() > 0) {for (Node methodNode : methodNodes) {
// 找到每个办法的参数列表申明
List<ASTFormalParameters> 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 文件中
<rule name="MethodParameterCountRule"
language="java"
message="java.oop.MethodParameterCountRule.rule.msg"
class="com.alibaba.p3c.pmd.lang.java.rule.oop.MethodParameterCountRule">
<!-- 级别,1 强制,2 举荐,3 参考 -->
<priority>1</priority>
<example>
<![CDATA[
Negative example:
public void methodB(int a, int b, int c, int d, int e) {}]]>
</example>
<example>
<![CDATA[
Positive example:
public void methodA() {}
]]>
</example>
</rule>
4.2.5.p3c-pmd 我的项目编写提示信息
上两步应用的提示信息和规定信息须要编写到 message.xml 配置文件中,message_en.xml 中是英文提醒,这里就先不演示了
<entry key="java.oop.MethodParameterCountRule.violation.msg">
<![CDATA[办法【%s】参数列表过长。]]>
</entry>
<entry key="java.oop.MethodParameterCountRule.rule.msg">
<![CDATA[阐明:办法参数列表不容许超过(含)5 个,倡议封装到一个对象中。]]>
</entry>
4.2.6. 单元测试
编写测试样例,将要测试的源代码写到 test 目录对应的 xml 文件中
举荐一个 Spring Boot 基础教程及实战示例:
https://github.com/javastacks…
<?xml version="1.0" encoding="UTF-8"?>
<test-data>
<code-fragment id="测试样例">
<![CDATA[
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) {}}
]]>
</code-fragment>
<test-code>
<!-- 预期问题个数 -->
<expected-problems>0</expected-problems>
<code-ref id="测试样例" />
</test-code>
</test-data>
编写单元测试
运行单元测试,因为样例代码中 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 中就行
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.8</version>
<configuration>
<rulesets>
<ruleset>rulesets/java/ali-comment.xml</ruleset>
<ruleset>rulesets/java/ali-concurrent.xml</ruleset>
<ruleset>rulesets/java/ali-constant.xml</ruleset>
<ruleset>rulesets/java/ali-exception.xml</ruleset>
<ruleset>rulesets/java/ali-flowcontrol.xml</ruleset>
<ruleset>rulesets/java/ali-naming.xml</ruleset>
<ruleset>rulesets/java/ali-oop.xml</ruleset>
<ruleset>rulesets/java/ali-orm.xml</ruleset>
<ruleset>rulesets/java/ali-other.xml</ruleset>
<ruleset>rulesets/java/ali-set.xml</ruleset>
</rulesets>
<printFailingErrors>true</printFailingErrors>
<!-- 扫描级别,小于等于这个级别的错误代码将不通过扫描。不配默认是 5 -->
<minimumPriority>1</minimumPriority>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.alibaba.p3c</groupId>
<artifactId>p3c-pmd</artifactId>
<version>1.3.3</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
如果存在不符合规范代码打包将失败:
对于 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 开发手册(嵩山版)》最新公布,速速下载!
感觉不错,别忘了顺手点赞 + 转发哦!