前言
CheckStyle 是一个帮助 Java 开发人员遵守代码规范的工具,它能够自动化代码规范检查过程,从而使得开发人员从这项重要但枯燥的任务中解脱。
我们会发现,GitHub 上很多开源项目都有个 checkstyle.xml,目的是希望大家能够准守约定的代码规范去贡献代码。所以 CheckStyle 的出现,主要是服务于多人协作的项目,如果你们的团队也很注重代码规范且人工审查它,那就赶紧用上 CheckStyle 吧。
CheckStyle 检验的内容
- Javadoc 注释
- 命名约定
- 标题
- import 语句
- 体积大小
- 空白
- 修饰符
- 块
- 代码问题
- 类设计
- 混合检查
定制 CheckStyle.xml
下面是根据我所在团队的代码规范定制的,每个团队可能不一样,更多的 CheckStyle 配置可看官网的说明。
所有的 <module/>
都有对应的 <message/>
,<message/>
是不符合规范的代码的提示语,可自定义。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<property name="severity" value="warning"/>
<module name="FileTabCharacter"> <property name="eachLine" value="true"/> <message key="name.containsTab" value="文件中不能含有 tab 制表符。"/> </module>
<module name="TreeWalker">
<module name="AvoidStarImport"/>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<module name="JavadocType"> <property name="tokens" value="CLASS_DEF"/> <property name="allowUnknownTags" value="true"/> <message key="javadoc.missing" value="类缺少 Javadoc 注释。"/> </module>
<module name="JavadocType"> <property name="tokens" value="INTERFACE_DEF"/> <property name="allowUnknownTags" value="true"/> <message key="javadoc.missing" value="接口缺少 Javadoc 注释。"/> </module>
<module name="JavadocType"> <property name="tokens" value="ENUM_DEF"/> <property name="allowUnknownTags" value="true"/> <message key="javadoc.missing" value="枚举缺少 Javadoc 注释。"/> </module>
<module name="JavadocType"> <property name="tokens" value="ANNOTATION_DEF"/> <property name="allowUnknownTags" value="true"/> <message key="javadoc.missing" value="注解缺少 Javadoc 注释。"/> </module>
<module name="ModifierOrder"> <message key="mod.order" value="修饰符需遵循如下顺序:public、protected、private、abstract、 static、final、transient,volatile、synchronized、native、strictfp。"/> </module>
<module name="LeftCurly"> <message key="line.previous" value="起始大括号的命名规范:''{0}'' 应在前一行。"/> </module> <module name="RightCurly"/>
<module name="GenericWhitespace"> <message key="ws.followed" value="泛型的命名规范:''{0}'' 后不应有空格。"/> <message key="ws.preceded" value="泛型的命名规范:''{0}'' 前不应有空格。"/> </module>
<module name="ParenPad"> <message key="ws.followed" value="方法参数的命名规范:''{0}'' 后不应有空格。"/> <message key="ws.preceded" value="方法参数的命名规范:''{0}'' 前不应有空格。"/> </module>
<module name="MethodParamPad"> <message key="ws.preceded" value="方法的命名规范:''{0}'' 前不应有空格。"/> </module>
<module name="TypecastParenPad"> <message key="ws.followed" value="类型转换的命名规范:''{0}'' 后不应有空格。"/> <message key="ws.preceded" value="类型转换的命名规范:''{0}'' 前不应有空格。"/> </module>
<module name="PackageName"> <message key="name.invalidPattern" value="包名的命名规范:全部小写。"/> </module>
<module name="TypeName"> <property name="tokens" value="CLASS_DEF"/> <message key="name.invalidPattern" value="类的命名规范:单个大写字母。"/> </module>
<module name="TypeName"> <property name="tokens" value="INTERFACE_DEF"/> <message key="name.invalidPattern" value="接口的命名规范:单个大写字母。"/> </module>
<module name="TypeName"> <property name="tokens" value="ENUM_DEF"/> <message key="name.invalidPattern" value="枚举的命名规范:单个大写字母。"/> </module>
<module name="TypeName"> <property name="tokens" value="ANNOTATION_DEF"/> <message key="name.invalidPattern" value="注解的命名规范:单个大写字母。"/> </module>
<module name="ClassTypeParameterName"> <message key="name.invalidPattern" value="类的类型参数的命名规范:单个大写字母。"/> </module>
<module name="InterfaceTypeParameterName"> <message key="name.invalidPattern" value="接口的类型参数的命名规范:单个大写字母。"/> </module>
<module name="MethodTypeParameterName"> <message key="name.invalidPattern" value="方法的类型参数的命名规范:单个大写字母。"/> </module>
<module name="ConstantName"> <message key="name.invalidPattern" value="常量的命名规范:大写字母或下划线。"/> </module>
<module name="StaticVariableName"> <property name="format" value="^(s|is)[A-Z][a-zA-Z0-9]*$"/> <message key="name.invalidPattern" value="静态变量的命名规范:s前缀+大写驼峰(布尔型的变量可使用 is 前缀)。"/> </module>
<module name="MemberName"> <property name="format" value="^(m|is)[A-Z][a-zA-Z0-9]*$"/> <message key="name.invalidPattern" value="成员变量的命名规范:m前缀+大写驼峰(布尔型的变量可使用 is 前缀)。"/> </module>
<module name="MethodName"> <message key="name.invalidPattern" value="方法名的命名规范:小写驼峰。"/> </module>
<module name="ParameterName"> <message key="name.invalidPattern" value="方法参数的命名规范:小写驼峰。"/> </module>
<module name="LocalFinalVariableName"> <message key="name.invalidPattern" value="局部的 final 类型变量的命名规范:小写驼峰。"/> </module>
<module name="LocalVariableName"> <message key="name.invalidPattern" value="局部的非 final 类型变量的命名规范:小写驼峰。"/> </module>
<module name="OuterTypeNumber"> <message key="maxOuterTypes" value="一个文件只能有一个根类。"/> </module>
<module name="AnonInnerLength"> <property name="max" value="60"/> <message key="maxLen.anonInner" value="内部类过长或数量过多,请将内部类抽离成独立类。"/> </module>
<module name="MethodCount"> <property name="maxTotal" value="30"/> <message key="too.many.methods" value="方法数量过多,请遵守单一职责设计原则。"/> </module>
<module name="ParameterNumber"> <property name="max" value="5"/> <property name="tokens" value="METHOD_DEF"/> <message key="maxParam" value="方法的参数不能超过5个,请使用对象包装。"/> </module>
<module name="MethodLength"> <property name="tokens" value="METHOD_DEF"/> <property name="max" value="60"/> <message key="maxLen.method" value="方法做的事情太多,请拆分成多个方法。"/> </module>
<module name="LineLength"> <property name="max" value="120"/> <message key="maxLineLen" value="单行代码过长,请换行。"/> </module>
<module name="DefaultComesLast"> <message key="default.comes.last" value="default 应为 switch 块最后一个元素。"/> </module>
<module name="MissingSwitchDefault"> <message key="missing.switch.default" value="switch 块未定义 default 。"/> </module>
<module name="EmptyStatement"> <message key="empty.statement" value="请移除空语句。"/> </module>
<module name="EqualsAvoidNull"> <message key="equals.avoid.null" value="为防止空指针异常,字符串常量应出现在 equals 比较的左侧。"/> <message key="equalsIgnoreCase.avoid.null" value="为防止空指针异常,字符串常量应出现在 equals 比较的左侧。"/> </module>
<module name="EqualsHashCode"> <message key="equals.noEquals" value="重载 ''hashCode()'' 方法后,必须重载 ''equals()'' 方法。"/> <message key="equals.noHashCode" value="重载 ''equals()'' 方法后,必须重载 ''hashCode()'' 方法。"/> </module>
<module name="StringLiteralEquality"> <message key="string.literal.equality" value="字符串应使用 ''equals()'' 方法进行比较,而非 ''{0}''。"/> </module>
<module name="MagicNumber"> <message key="magic.number" value="请将 ''{0}'' 替换成常量。"/> </module>
<module name="OneStatementPerLine"> <message key="multiple.statements.line" value="每行只能声明一个变量。"/> </module>
<module name="MultipleVariableDeclarations"> <message key="multiple.variable.declarations" value="每行只能定义一个变量。"/> </module>
<module name="NestedForDepth"> <property name="max" value="2"/> <message key="nested.for.depth" value="至多 3 层 for 嵌套。"/> </module>
<module name="NestedIfDepth"> <property name="max" value="2"/> <message key="nested.if.depth" value="至多 3 层 if 嵌套。"/> </module>
<module name="NestedTryDepth"> <property name="max" value="2"/> <message key="nested.try.depth" value="至多 3 层 try 嵌套。"/> </module>
<module name="SimplifyBooleanReturn"> <message key="simplify.boolReturn" value="不必要的条件逻辑。"/> </module>
<module name="Regexp"> <property name="format" value="System\.(out|err)\.print*"/> <property name="illegalPattern" value="true"/> <message key="illegal.regexp" value="请使用 Log 打印日志。"/> </module> </module> </module>
|
搭配 Android Studio
由于团队默认使用 Android Studio 开发,自然是将 CheckStyle 跟 Android Studio 结合起来了。我们想达到的效果是能实时检查不规范的代码并给出纠正的提示语,这是没问题的。下面是具体配置流程。
下载 CheckStyle 插件
在 Android Studio 的 Plugins 中下载最新版本的 CheckStyle-IDEA。
添加 CheckStyle
在项目根目录下添加 checkstyle.xml 文件。
关联 CheckStyle
CheckStyle 实时检查
CheckStyle 手动检查