工作中不知道你是否遇到过这种问题:你维护了一个基础库,在迭代过程中由于业务变化或代码优化,不得不对一些接口进行重构,这个过程中就可能会产生少量废弃接口。虽然你出于谨慎将这些接口标记为@Deprecated,但是仍然会有开发者不注意,使用被废弃的接口,造成后期维护上的一些问题。我们可以通过编码规范来处理此类问题,本文主要来谈谈编码规范及其实施办法。
有规可依
谈到编码规范,首先要解决的是有法可依的问题。代码改怎么写才算规范,这个问题在任何大厂都是有丰富的实践经验和血泪教训的,在网上找到了一份《Google 开源项目风格指南——中文版》,包含了下述语言的编码规范:
上述文档github地址:https://github.com/zh-google-styleguide/zh-google-styleguide
执规必严
有了规范下一步就是如何实施的问题了。
Lint
IDE内置Lint工具可以帮助我们静态分析代码中存在的不规范的地方,并通过标记色和warn日志进行提示。
其支持检出:
- xml文件中是否存在hardcode硬编码
- unused resources没有使用到的资源
- spelling拼写问题
- probable bug等
gradle选项:
android {
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
.....
}
Lint检查可以提示可能存在的问题,但是默认不会造成编译失败,对于error级别的隐患,可配置
abortOnError true
达到强制修改的作用
基本使用
- Analyze>Inspect Code:
- 选择检查范围,通常为whole project
- 查看检查结果
Inspections配置
IDE支持我们配置Lint的检查项和提示等级,在Setings>Inspections中:
同样,检查结果只能起到提醒作用
Lint API
从上一节可以看到Inspections支持我们自定义Lint检查项,那如果我们需要进一步的增加自己的检查项呢?比如:
- 检查是否使用了系统的Toast,提示使用统一的toast;
- 检测文本表达式中是否包含特定的字符串;
- 检测所有 layout 或 java 文件中引用的 png 资源,提示使用 webp;
- 检测使用 Log 类的 i、d、e 等日志输出的方法,提示使用统一的日志工具类;
- 检测直接通过 new Thread 创建线程,提示应该使用统一线程池;
这时候需要Lint API出场了,使用方法主要分为如下几步:
- 创建 java library 模块
compileOnly "com.android.tools.lint:lint-api:26.4.1"
compileOnly "com.android.tools.lint:lint-checks:26.4.1"
- 创建 Detector
public class SampleDetector extends Detector implements Detector.UastScanner {
//第一步:定义 ISSUE
public static final Issue ISSUE = Issue.create( "ShortUniqueId", //唯一 ID
"Lint Mentions", //简单描述
"Blah blah blah.", //详细描述
Category.CORRECTNESS, //问题种类(正确性、安全性等)
6, //权重
Severity.WARNING, //问题严重程度(忽略、警告、错误)
new Implementation( //实现,包括处理实例和作用域
SampleCodeDetector.class,
Scope.JAVA_FILE_SCOPE));
//第二步:定义检测类型以及处理逻辑
// 检测类型包括文本表达式、调用相关表达式等
@Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Collections.singletonList(ULiteralExpression.class);
}
@Override
public UElementHandler createUastHandler(@NotNull JavaContext context) {
return new UElementHandler() {
@Override
public void visitLiteralExpression(@NotNull ULiteralExpression expression) {
String string = UastLiteralUtils.getValueIfStringLiteral(expression);
if (string == null) {
return;
}
if (string.contains("Omooo") && string.matches(".*\\bOmooo\\b.*")) {
//第三步:符合条件,上报 ISSUE
context.report(ISSUE, expression, context.getLocation(expression), "This code mentions `Omooo`");
}
}
};
}
}
- 注册 Detector
public class CustomIssueRegistry extends IssueRegistry {
@NotNull
@Override
public List<Issue> getIssues() {
return Arrays.asList(SampleCodeDetector.ISSUE);
}
@Override
public int getApi() {
return ApiKt.CURRENT_API;
}
}
- 配置Lint编译选项
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
compileOnly "com.android.tools.lint:lint-api:26.4.1"
compileOnly "com.android.tools.lint:lint-checks:26.4.1"
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
jar {
manifest {
attributes("Lint-Registry-v2": "top.omooo.lint_library.CustomIssueRegistry")
}
}
- 项目引入自定义 Lint
// 在需要检查的module gradle中引入
dependencies {
lintChecks project(":lint_library")
}
详细使用方法参见:你必须要了解的 AndroidStudio 3.x Lint API
Alibaba Java Coding Guidelines
该IDE插件由阿里巴巴 P3C 项目组研发。代码已经开源https://github.com/alibaba/p3c,以及官方宣传文章《阿里巴巴Java开发规约》插件全球首发!。
特性:
- 支持静态检测,和基于 Inspection 机制的实时检测功能;
- 检测结果分为三个等级(Blocker崩溃/Critical严重/Major重要),其中前两级必须要处理掉;
- 支持批量一键修复的功能;
插件安装和使用比较简单可以参考网上的博客,目前没有找到自定义检测项或规则的拓展功能,
CheckStyle
CheckStyle作为检验代码规范的插件,除了可以使用配置默认给定的开发规范(Sun/Google开发规范),也可以导入像阿里的开发规范的插件。每一个公司都存在不同的开发规范要求,所以大部分公司会给定自己的check规范,一般导入给定的checkstyle.xml文件即可实现。
特性:
- 支持源码/jar检测;
- 自带Sun/Google开发规范;
- 支持配置自己的编码规范,导入即可;
使用方法参考:CheckStyle使用
FindBugs
FindBugs也是一款IDE插件,用法跟其他工具也差不多,使用方法可以查找网上的资料。
使用方法参考:FindBugs:简介与使用