概述
Checkstyle是一个开发工具,用于帮助程序员编写符合编码标准的Java代码。它使检查Java代码的过程自动化,从而使人们不必承担这项乏味(但重要)的任务。这对于想要执行编码标准的项目来说是非常理想的。
Checkstyle是高度可配置的,可以支持几乎任何编码标准。提供了一个示例配置文件,该文件支持Sun代码约定、谷歌Java风格。
集成方式
可以通过gradle插件和gradle脚本两种方式来实现。下面列一下两种方式的有点:
- gradle插件:可以把扫描结果输出到.html和.xml文件中。
- gradle脚本:可以直接点击问题跳转到源码处,方便快速查看。
Gradle脚本
首先在工程根目录(其它位置也可以)下创建配置文件夹codestyles/checkstyle。然后在创建checkstyle.xml文件用于存放代码规范配置,创建checkstyle.gradle用于配置插件和脚本。文件目录如下图:
checkstyle.gradle文件内容
allprojects { org.gradle.api.Project project ->
apply plugin: 'checkstyle'
checkstyle {
configFile rootProject.file('codestyles/checkstyle/checkrlues.xml')
toolVersion '8.23'
ignoreFailures false
showViolations true
}
task('checkstyle', type: Checkstyle) {
source 'src/main/java'
include '**/*.java'
exclude '**/R.java', '**/BuildConfig.java'
classpath = files()
}
project.afterEvaluate {
}
}
checkstyle.xml配置文件
<?xml version="1.0"?><!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="TreeWalker">
<!-- Annotations-->
<!-- 注解位置-->
<module name="AnnotationLocation">
<property name="allowSamelineMultipleAnnotations" value="false" />
<property name="allowSamelineSingleParameterlessAnnotation" value="false" />
<property name="allowSamelineParameterizedAnnotation" value="false" />
</module>
<!-- Block-->
<!--检查空代码块-->
<module name="EmptyBlock" />
<!--定义左大括号位置-->
<module name="LeftCurly">
<property name="option" value="eol" />
<property name="tokens" value="CLASS_DEF,INTERFACE_DEF,METHOD_DEF,CTOR_DEF" />
</module>
<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>
<!--检查空Catch块-->
<module name="EmptyCatchBlock">
<property name="exceptionVariableName" value="expected|ignore" />
</module>
<!--缺少括号-->
<module name="NeedBraces">
<property name="allowSingleLineStatement" value="true" />
<property name="tokens" value=" LITERAL_DO, LITERAL_ELSE, LITERAL_FOR, LITERAL_IF, LITERAL_WHILE, LAMBDA" />
</module>
<!-- Javadoc-->
<!--<module name="JavadocType">-->
<!-- <property name="authorFormat" value="\S" />-->
<!-- <property name="tokens" value="CLASS_DEF,INTERFACE_DEF" />-->
<!--</module>-->
<!-- Naming -->
<!--常量命名-->
<module name="ConstantName" />
<module name="ClassTypeParameterName">
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''." />
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)" />
</module>
<!--lambda 参数命名-->
<module name="LambdaParameterName" />
<!--接口注解命名-->
<module name="InterfaceTypeParameterName" />
<module name="MethodTypeParameterName" />
<module name="MethodName" />
<module name="ParameterName" />
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$" />
</module>
<module name="TypeName">
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''." />
</module>
<!-- Imports-->
<module name="RedundantImport" />
<module name="UnusedImports" />
<!--Modifiers-->
<!--Coding -->
<module name="CovariantEquals" />
<module name="EmptyStatement" />
<module name="EqualsAvoidNull" />
<module name="EqualsHashCode" />
<module name="NestedTryDepth">
<property name="max" value="3" />
</module>
<module name="SimplifyBooleanExpression" />
<module name="SimplifyBooleanReturn" />
<module name="StringLiteralEquality" />
<module name="EqualsAvoidNull" />
<module name="ExplicitInitialization">
<property name="onlyObjectReferences" value="true" />
</module>
<!--switch 缺少break return语句-->
<module name="FallThrough" />
<module name="OneStatementPerLine" />
<module name="RequireThis" />
<module name="UnnecessaryParentheses" />
<module name="UnnecessarySemicolonInEnumeration" />
<module name="UnnecessarySemicolonInTryWithResources" />
<module name="DefaultComesLast" />
<module name="HiddenField" >
<property name="ignoreConstructorParameter" value="true"/>
<property name="ignoreSetter" value="true"/>
</module>
<module name="IllegalInstantiation" />
<!--for嵌套层次-->
<module name="NestedForDepth">
<property name="max" value="3" />
</module>
<!--if 嵌套层数-->
<module name="NestedIfDepth">
<property name="max" value="4" />
</module>
<!--try catch嵌套层数-->
<module name="NestedTryDepth">
<property name="max" value="3" />
</module>
<!--非法字符-->
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL" />
<property name="format"
value="\\u00(08|09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)" />
<property name="message" value="Avoid using corresponding octal or Unicode escape." />
</module>
<!--Class Design-->
<!--class 名称需和文件名一致-->
<module name="OneTopLevelClass" />
<module name="NoFinalizer" />
<!--Miscellaneous-->
<module name="ArrayTypeStyle" />
<module name="UpperEll" />
<module name="OuterTypeFilename" />
<!--Regexp-->
<module name="RegexpSinglelineJava">
<!-- . matches any character, so we need to
escape it and use \. to match dots. -->
<property name="format" value="System\.out\.println" />
<property name="ignoreComments" value="true" />
</module>
<!--Size Violations-->
<module name="LineLength">
<property name="max" value="120" />
<property name="ignorePattern"
value="^package.*|^import.*|a href|href|http://|https://|ftp://|^\s*//.*" />
</module>
<!--<module name="ParameterNumber" />-->
<!--Whitespace-->
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true" />
</module>
<module name="MethodParamPad" />
<module name="NoWhitespaceBefore">
<property name="tokens"
value="COMMA, SEMI, POST_INC, POST_DEC, DOT, ELLIPSIS, METHOD_REF" />
<property name="allowLineBreaks" value="true" />
</module>
<module name="ParenPad" />
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapDot" />
<property name="tokens" value="DOT" />
<property name="option" value="nl" />
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapComma" />
<property name="tokens" value="COMMA" />
<property name="option" value="EOL" />
</module>
<module name="SeparatorWrap">
<property name="id" value="SeparatorWrapMethodRef" />
<property name="tokens" value="METHOD_REF" />
<property name="option" value="nl" />
</module>
</module>
<property name="fileExtensions" value="java, properties, xml, vm, g, g4, dtd, kt" />
<property name="charset" value="UTF-8" />
<property name="severity" value="error" />
</module>
在project的build.gradle中引入checkstyle.gradle。
//引用checkstyle.gradle
apply from:'codestyles/checkstyle/checkstyle.gradle'
buildscript {
ext.kotlin_version = '1.3.61'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
执行代码规范检测:在右边栏点击Gradle,在Tasks组别中找到other组,然后找到checkstyle任务,点击执行。
生成的report报告位置module/build/reports
Gradle插件
插件搜索下载,下载成功之后需要重启IDE。
重新启动IDE之后会在底部栏新增一个CheckStyle,在Rules:下拉选框中默认会有两个已经配置好的代码规范,Sun Checks和GoogleChecks,可以先勾选Google Checks如下图所示:
然后点击左侧按钮进行检测,检测范围可以是整个项目,改动的项目等。检测结果如下图:
同时在AS设置Preferences->Other Settings->Check Style,也可以进行设置。