为了规范编码,使用到了CheckStyle。
CheckStyle的主要功能就是实时检测,代码的规范(Code Style)是否符合我们规定的一个模板,如代码和括号之间没有空格, 类中导入的包没有使用等,当发现这些不符合这些规范时,它就报一个警告或者错误等提示,导致编译不通过。
CheckStyle检验的主要内容
- Javadoc注释
- 命名约定
- 标题
- Import语句
- 体积大小
- 空白
- 修饰符
- 块
- 代码问题
- 类设计
- 混合检查(包活一些有用的比如非必须的System.out和printstackTrace)
那么,怎么使用代码检测呢?
checkstyle帮助开发者实现常用JAVA代码规范的自动化检查。它的功能比较丰富,相对配置起来比较复杂,你需要根据自己的需求配置你想检查的东西,比如Annotations,Block Checks,Class Design,Coding,Duplicate Code,Headers,Imports,Javadoc Comments,Metrics,Miscellaneous,Modifiers,Naming Conventions,Regexp,Size Violations,Whitespace。
在Android开发中,也需要我们去定义,Android Studio继承了IDEA的可拓展特性,它也拥有CheckStyle的插件,在Android项目中,使用的Gradle配置。
一、自定义checkstyle插件的check.gradle
/*
* 检查代码规范
*/
apply plugin: 'checkstyle'
//设置CheckStyle版本
checkstyle {
ignoreFailures = false
showViolations true
toolVersion '8.0'
}
//设置配置文件
task checkstyle(type: Checkstyle) {
description 'Check code standard'
group 'verification'
configFile file("${project.rootDir}/buildConfig/checkstyle.xml")
source 'src'
include '**/*.java'
exclude '**/gen/**'
exclude '**/test/**'
exclude '**/androidTest/**'
classpath = files()
}
// 每次编绎时都进行checkstyle检测
project.afterEvaluate {
preBuild.dependsOn 'checkstyle'
}
二、设置配置文件checkstyle.xml,定义我们想要校验的内容
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
<module name="Checker">
<!-- 更多配置情况参见: http://blog.youkuaiyun.com/yang1982_0907/article/details/18086693 -->
<property name="charset" value="UTF-8" />
<property name="severity" value="error" />
<!-- Checks for Size Violations. -->
<!-- 检查文件的长度(行) default max=2500 -->
<module name="FileLength">
<property name="max" value="3000" />
<property name="severity" value="warning" />
</module>
<!-- 检查源码中没有制表符('\t') -->
<module name="FileTabCharacter">
<property name="eachLine" value="true" />
</module>
<module name="TreeWalker">
<module name="SuppressWarningsHolder" />
<!--空格检测-->
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true" />
<property name="allowEmptyMethods" value="true" />
<property name="allowEmptyTypes" value="true" />
<property name="allowEmptyLoops" value="true" />
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace." />
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace." />
</module>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace." />
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace." />
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace." />
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace." />
</module>
<!-- Checks for imports -->
<!-- 必须导入类的完整路径,即不能使用*导入所需的类 -->
<module name="AvoidStarImport" />
<!-- 检查是否从非法的包中导入了类 illegalPkgs: 定义非法的包名称-->
<module name="IllegalImport" /> <!-- defaults to sun.* packages -->
<!-- 检查是否导入了不必显示导入的类-->
<module name="RedundantImport" />
<!-- 检查是否导入的包没有使用-->
<module name="UnusedImports" />
<!-- 检查代码块的左花括号的放置位置 -->
<module name="LeftCurly">
<property name="option" value="eol" />
</module>
<!--检查代码块周围是否有大括号,可以检查do、else、if、for、while等关键字所控制的代码块-->
<module name="NeedBraces">
<property name="tokens"
value="LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_WHILE" /> <!-- LITERAL_IF 不检测-->
<property name="allowSingleLineStatement" value="true" />
</module>
<!--检查else、try、catch标记的代码块的右花括号的放置位置-->
<module name="RightCurly">
<property name="id" value="RightCurlySame" />
<property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_DO" />
</module>
<module name="RightCurly">
<property name="id" value="RightCurlyAlone" />
<property name="option" value="alone" />
<property name="tokens"
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT, INSTANCE_INIT" />
</module>
<!-- 检查在重写了equals方法后是否重写了hashCode方法 -->
<module name="EqualsHashCode" />
<!--检查是否有不合法的实例化操作,是否使用工厂方法更好-->
<module name="IllegalInstantiation">
<property name="classes" value="java.lang.Boolean" />
</module>
<!--检查Java代码的缩进是否正确-->
<module name="Indentation">
<property name="arrayInitIndent" value="8" />
</module>
<module name="SimplifyBooleanExpression" />
<module name="SimplifyBooleanReturn" />
<!--检查每个变量是否使用一行一条语句进行声明-->
<!--<module name="MultipleVariableDeclarations" />-->
<!--检查数组定义的风格,默认java风格-->
<module name="ArrayTypeStyle" />
<!--检查long类型的常量在定义时是否由大写的“L”开头-->
<module name="UpperEll" />
<!--检查switch中case后是否加入了跳出语句,例如:return、break、throw、continue -->
<module name="FallThrough" />
<!-- Checks the number of parameters of a method or constructor. max default 7个. -->
<module name="ParameterNumber">
<property name="max" value="19" />
</module>
<!-- 每行字符数 -->
<module name="LineLength">
<property name="max" value="250" />
</module>
<!-- Checks for long methods and constructors. max default 150行. max=300 设置长度300 -->
<module name="MethodLength">
<property name="max" value="200" />
</module>
<!-- ModifierOrder 检查修饰符的顺序,默认是 public,protected,private,abstract,static,final,transient,volatile,synchronized,native -->
<module name="ModifierOrder" />
<!-- 检查是否有多余的修饰符,例如:接口中的方法不必使用public、abstract修饰 -->
<!--<module name="RedundantModifier">-->
<!--</module>-->
<!--- 字符串比较必须使用 equals() -->
<module name="StringLiteralEquality" />
<!--限制try代码块的嵌套层数(默认值为1)-->
<module name="NestedTryDepth">
<property name="max" value="2" />
</module>
<!-- 返回个数 -->
<module name="ReturnCount">
<property name="max" value="15" />
<property name="maxForVoid" value="15" />
<property name="format" value="^$" />
</module>
</module>
</module>
三、在项目中引入check.gradle即可。我将其引入到app的build.gradle中
//代码检查checkstyle
apply from: '../buildConfig/check.gradle'
编译
然后,根据错误提示,找到对应的错误,修复即可。
代码检测的使用就这样了。
》》》有可能会遇到的问题
一、Unexpected character 0xfeff in identifier
Caused by: F:\project\work\AppFleet_Android\app\src\main\java\com\fleet\statistics\StatisticsUtil.java:1:1: Unexpected character 0xfeff in identifier
at com.puppycrawl.tools.checkstyle.grammars.GeneratedJavaLexer.nextToken(GeneratedJavaLexer.java:405)
at antlr.TokenStreamHiddenTokenFilter.consume(TokenStreamHiddenTokenFilter.java:38)
at antlr.TokenStreamHiddenTokenFilter.consumeFirst(TokenStreamHiddenTokenFilter.java:42)
at antlr.TokenStreamHiddenTokenFilter.nextToken(TokenStreamHiddenTokenFilter.java:122)
at antlr.TokenBuffer.fill(TokenBuffer.java:69)
at antlr.TokenBuffer.LA(TokenBuffer.java:80)
at antlr.LLkParser.LA(LLkParser.java:52)
at com.puppycrawl.tools.checkstyle.grammars.GeneratedJavaRecognizer.compilationUnit(GeneratedJavaRecognizer.java:158)
at com.puppycrawl.tools.checkstyle.TreeWalker.parse(TreeWalker.java:446)
at com.puppycrawl.tools.checkstyle.TreeWalker.processFiltered(TreeWalker.java:179)
... 67 more
这是因为:出错的Java文件编码和CheckStyle设置的编码不同。CheckStyle里设置的编码是UTF-8。
而Java文件的编码可以通过编辑器Notepad++打开查看,如下
将Java文件的编码改为UTF-8编码即可,不要带BOM。
二、member def modifier
就这个类,一直编译不通过,我仔细检查了,没有其他问题啊,但是报的错表示这个类的所有代码都有问题,那我想会不会是代码编码问题,看了一下,都是UTF-8,没问题。既然编码没问题,那会不会是格式的问题。仔细一看,果真,就是格式化的问题。用Ctrl + Shift +F 格式化一下就好了。
编码过程中,多使用格式化。